如何在没有临时 Table 的情况下使用 SQL 光标跳过一行
How do a Skip a Row With SQL Cursor without a Temp Table
我在 SQL 中有一个很大的 table,包含以下列:
CompanyId(int)
Email(Varchar 255)
First_Name(Varchar 50)
Last_Name(Varchar 50)
1
jim_halpert@dundermifflin.com
Jim
Halpert
2
bvance@vancerefridgerations.com
Bob
Vance
1
michael_scott@dundermifflin.com
Michael
Scott
CompanyId 可以重复多次,因为公司会附加到各种电子邮件中。
我的雇主要我查找属于特定类型的公司电子邮件。在几个 IF 语句之后,最终结果将打印如下消息:
"CompanyId" has firstName_lastName@companyName.domain type email
"CompanyId" has firstInitial_lastName@companyName.domain type email
我的雇主告诉我使用 Cursor 来找到我的解决方案,但是一旦我启动了我的游标,我需要检查 CompanyId 以查看该 ID 是否已经被循环并找到了一个类型。如果CompanyId已经循环过了,我想跳过。
这是我到目前为止的代码
DECLARE @CoId INT
,@Email VARCHAR(255)
,@FName varchar(50)
,@LName varchar(50)
Declare @condition bit = 1
Declare CoCursor CURSOR
For SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Email as E
Left Join Table_People as P
ON E.EmployeeID = P.EmployeeID
Order by CompanyID, Email
-- Loop through the rows with Cursors for CompanyId and Email
OPEN CoCursor
Fetch NEXT FROM CoCursor
INTO @CoId, @Email, @FName, @LName
While @@FETCH_STATUS = 0
BEGIN
-- Check to see if CompanyId has been logged before, if not, proceed
-- Check to see if email matches criteria
IF @Email LIKE @FName + '[_]' + @LName + '@%'
BEGIN
-- If yes, check next email where CompanyIds match
;WITH EmailTable(CompanyID, Email, First_Name, Last_Name) AS (
SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Emails as E
Left Table_People as P
ON E.EmployeeID = P.EmployeeID
Where E.CompanyID = @CoId
And E.Email LIKE P.First_Name + '[_]' + P.Last_Name + '@%')
Select TOP(2) @condition = 0
FROM EmailTable
Having COUNT(*) > 1
-- If email matches previous email, log Company Id with the email type
IF @condition = 0
PRINT CONVERT(VARCHAR(50), @CoId) + ' has email like firstName_lastName@CompanyAddress.domain'
-- If not, go to next Email check
END
IF @Email LIKE LEFT(@FName,1) + @LName + '@%'
-- If yes, check next email where CompanyIds match
-- If email matches previous email, log Company Id with the email type
-- If it has been logged move onto next record.
Fetch NEXT FROM CoCursor
INTO @CoId, @Email, @FName, @LName
-- Once the result is logged go to next row
END
CLOSE CoCursor
DEALLOCATE CoCursor
我看到的一个解决方案使用临时 table 来记录以前使用过的 ID,但我的雇主不希望我使用临时 table。
How Can I Skip a row(an iteration) in MSSQL Cursor based on some condition?
谢谢!
游标速度慢且效率低下,很少需要。
这根本不需要游标。一个带有 group by
的简单过滤连接就足够了
SELECT
CONCAT(e.CompanyID), ' has email like firstName_lastName@CompanyAddress.domain')
FROM Table_Email e
JOIN Table_People p ON p.EmployeeID = e.EmployeeID
WHERE e.Email LIKE p.First_Name + '[_]' + p.Last_Name + '@%'
GROUP BY
e.CompanyID
ORDER BY
e.CompanyID;
显然,出于某些非常奇怪的原因,您的雇主强制 一个游标,我相信您会告诉他们不使用它们的所有原因。但不管怎样,你去吧:
你原来的代码还是很绕,你可以用上面的代码作为游标的SELECT
来简化一下
Note the use of a local variable for the cursor, this means you don't have to deallocate it
DECLARE @CompanyID int;
DECLARE @crsr CURSOR;
SET @crsr = CURSOR FAST_FORWARD FOR
SELECT
e.CompanyID
FROM Table_Email e
JOIN Table_People p ON p.EmployeeID = e.EmployeeID
WHERE e.Email LIKE p.First_Name + '[_]' + p.Last_Name + '@%'
GROUP BY
e.CompanyID
ORDER BY
e.CompanyID;
OPEN @crsr;
FETCH NEXT FROM @crsr
INTO @CompanyID;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT CONCAT(e.CompanyID), ' has email like firstName_lastName@CompanyAddress.domain');
FETCH NEXT FROM @crsr
INTO @CompanyID;
END;
CLOSE @crsr;
我不太喜欢游标,所以我将提出另一种可能的解决方案(我认为这是一个更好的解决方案,尽管您的雇主出于某种奇怪的原因想要游标)。
您的示例数据:
create table Table_Email (
CompanyID int,
EmployeeID int,
Email varchar(255)
)
create table Table_People (
CompanyID int,
EmployeeID int,
First_Name varchar(50),
Last_Name varchar(50),
)
insert into Table_Email values (1, 1, 'jim_halpert@dundermifflin.com')
insert into Table_Email values (2, 2, 'bvance@vancerefridgerations.com')
insert into Table_Email values (1, 3, 'michael_scott@dundermifflin.com')
insert into Table_People values (1, 1, 'Jim', 'Halpert')
insert into Table_People values (2, 2, 'Bob', 'Vance')
insert into Table_People values (1, 3, 'Michael', 'Scott')
我建议的查询:
SELECT CONVERT(VARCHAR(50), CompanyID) + ' has email like firstName_lastName@CompanyAddress.domain' FROM
(
SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Email as E Left Join Table_People as P
ON E.EmployeeID = P.EmployeeID
WHERE Email LIKE P.First_Name + '[_]' + P.Last_Name + '@%'
) AS a
group by CompanyID
order by CompanyID
它returns:
1 has email like firstName_lastName@CompanyAddress.domain
SQL Fiddle: http://sqlfiddle.com/#!18/4c30e8/1
使光标中的 CompanyId 不同
Declare CoCursor CURSOR
For Select CompanyID,
Email,
First_Name,
Last_Name
FROM (SELECT E.CompanyID,
E.Email,
P.First_Name,
P.Last_Name,
ROW_NUMBER() OVER(PARTITION BY E.CompanyID ORDER BY E.Email ASC) as RN
From Table_Emails as E
Left Table_People as P
ON E.EmployeeID = P.EmployeeID) as T
Where RN = 1
Order by CompanyID
我在 SQL 中有一个很大的 table,包含以下列:
CompanyId(int) | Email(Varchar 255) | First_Name(Varchar 50) | Last_Name(Varchar 50) |
---|---|---|---|
1 | jim_halpert@dundermifflin.com | Jim | Halpert |
2 | bvance@vancerefridgerations.com | Bob | Vance |
1 | michael_scott@dundermifflin.com | Michael | Scott |
CompanyId 可以重复多次,因为公司会附加到各种电子邮件中。
我的雇主要我查找属于特定类型的公司电子邮件。在几个 IF 语句之后,最终结果将打印如下消息:
"CompanyId" has firstName_lastName@companyName.domain type email
"CompanyId" has firstInitial_lastName@companyName.domain type email
我的雇主告诉我使用 Cursor 来找到我的解决方案,但是一旦我启动了我的游标,我需要检查 CompanyId 以查看该 ID 是否已经被循环并找到了一个类型。如果CompanyId已经循环过了,我想跳过。
这是我到目前为止的代码
DECLARE @CoId INT
,@Email VARCHAR(255)
,@FName varchar(50)
,@LName varchar(50)
Declare @condition bit = 1
Declare CoCursor CURSOR
For SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Email as E
Left Join Table_People as P
ON E.EmployeeID = P.EmployeeID
Order by CompanyID, Email
-- Loop through the rows with Cursors for CompanyId and Email
OPEN CoCursor
Fetch NEXT FROM CoCursor
INTO @CoId, @Email, @FName, @LName
While @@FETCH_STATUS = 0
BEGIN
-- Check to see if CompanyId has been logged before, if not, proceed
-- Check to see if email matches criteria
IF @Email LIKE @FName + '[_]' + @LName + '@%'
BEGIN
-- If yes, check next email where CompanyIds match
;WITH EmailTable(CompanyID, Email, First_Name, Last_Name) AS (
SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Emails as E
Left Table_People as P
ON E.EmployeeID = P.EmployeeID
Where E.CompanyID = @CoId
And E.Email LIKE P.First_Name + '[_]' + P.Last_Name + '@%')
Select TOP(2) @condition = 0
FROM EmailTable
Having COUNT(*) > 1
-- If email matches previous email, log Company Id with the email type
IF @condition = 0
PRINT CONVERT(VARCHAR(50), @CoId) + ' has email like firstName_lastName@CompanyAddress.domain'
-- If not, go to next Email check
END
IF @Email LIKE LEFT(@FName,1) + @LName + '@%'
-- If yes, check next email where CompanyIds match
-- If email matches previous email, log Company Id with the email type
-- If it has been logged move onto next record.
Fetch NEXT FROM CoCursor
INTO @CoId, @Email, @FName, @LName
-- Once the result is logged go to next row
END
CLOSE CoCursor
DEALLOCATE CoCursor
我看到的一个解决方案使用临时 table 来记录以前使用过的 ID,但我的雇主不希望我使用临时 table。 How Can I Skip a row(an iteration) in MSSQL Cursor based on some condition?
谢谢!
游标速度慢且效率低下,很少需要。
这根本不需要游标。一个带有 group by
的简单过滤连接就足够了
SELECT
CONCAT(e.CompanyID), ' has email like firstName_lastName@CompanyAddress.domain')
FROM Table_Email e
JOIN Table_People p ON p.EmployeeID = e.EmployeeID
WHERE e.Email LIKE p.First_Name + '[_]' + p.Last_Name + '@%'
GROUP BY
e.CompanyID
ORDER BY
e.CompanyID;
显然,出于某些非常奇怪的原因,您的雇主强制 一个游标,我相信您会告诉他们不使用它们的所有原因。但不管怎样,你去吧:
你原来的代码还是很绕,你可以用上面的代码作为游标的SELECT
来简化一下
Note the use of a local variable for the cursor, this means you don't have to deallocate it
DECLARE @CompanyID int;
DECLARE @crsr CURSOR;
SET @crsr = CURSOR FAST_FORWARD FOR
SELECT
e.CompanyID
FROM Table_Email e
JOIN Table_People p ON p.EmployeeID = e.EmployeeID
WHERE e.Email LIKE p.First_Name + '[_]' + p.Last_Name + '@%'
GROUP BY
e.CompanyID
ORDER BY
e.CompanyID;
OPEN @crsr;
FETCH NEXT FROM @crsr
INTO @CompanyID;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT CONCAT(e.CompanyID), ' has email like firstName_lastName@CompanyAddress.domain');
FETCH NEXT FROM @crsr
INTO @CompanyID;
END;
CLOSE @crsr;
我不太喜欢游标,所以我将提出另一种可能的解决方案(我认为这是一个更好的解决方案,尽管您的雇主出于某种奇怪的原因想要游标)。
您的示例数据:
create table Table_Email (
CompanyID int,
EmployeeID int,
Email varchar(255)
)
create table Table_People (
CompanyID int,
EmployeeID int,
First_Name varchar(50),
Last_Name varchar(50),
)
insert into Table_Email values (1, 1, 'jim_halpert@dundermifflin.com')
insert into Table_Email values (2, 2, 'bvance@vancerefridgerations.com')
insert into Table_Email values (1, 3, 'michael_scott@dundermifflin.com')
insert into Table_People values (1, 1, 'Jim', 'Halpert')
insert into Table_People values (2, 2, 'Bob', 'Vance')
insert into Table_People values (1, 3, 'Michael', 'Scott')
我建议的查询:
SELECT CONVERT(VARCHAR(50), CompanyID) + ' has email like firstName_lastName@CompanyAddress.domain' FROM
(
SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Email as E Left Join Table_People as P
ON E.EmployeeID = P.EmployeeID
WHERE Email LIKE P.First_Name + '[_]' + P.Last_Name + '@%'
) AS a
group by CompanyID
order by CompanyID
它returns:
1 has email like firstName_lastName@CompanyAddress.domain |
SQL Fiddle: http://sqlfiddle.com/#!18/4c30e8/1
使光标中的 CompanyId 不同
Declare CoCursor CURSOR
For Select CompanyID,
Email,
First_Name,
Last_Name
FROM (SELECT E.CompanyID,
E.Email,
P.First_Name,
P.Last_Name,
ROW_NUMBER() OVER(PARTITION BY E.CompanyID ORDER BY E.Email ASC) as RN
From Table_Emails as E
Left Table_People as P
ON E.EmployeeID = P.EmployeeID) as T
Where RN = 1
Order by CompanyID