我有一个使用游标的SQL查询,希望将其更快更快,并尝试提高我对新SQL技术的理解。我正在使用SQL Server 2008
将它粘贴在这里,因为SQLFiddle现在看起来很不稳定。
SET NOCOUNT ON
CREATE TABLE Person(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[Gx] [int] NULL,
[Gy] [int] NULL)
CREATE TABLE Location(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[Gx] [int] NULL,
[Gy] [int] NULL)
CREATE TABLE PersonLocation(
[ID] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[LocationId] [int] NULL)
INSERT INTO Person
(Name, Gx, Gy)
VALUES
('Alice',27287, 09641)
INSERT INTO Person
(Name, Gx, Gy)
VALUES
('Bob',54433, 26101)
INSERT INTO Location
(Name, Gx, Gy)
VALUES
('London',53007, 18027)
INSERT INTO Location
(Name, Gx, Gy)
VALUES
('Oxford',45142, 20563)
INSERT INTO PersonLocation
(PersonId, LocationId)
VALUES
(2,2)
DECLARE @Table TABLE (PersonId int, SetLocation bit, Distance float)
DECLARE @PersonId int, @Gx int = 0, @Gy int = 0
DECLARE Curs CURSOR FOR SELECT Id, Gx, Gy FROM PERSON
OPEN Curs
FETCH NEXT FROM Curs INTO @PersonId, @Gx, @Gy
WHILE @@Fetch_Status = 0
BEGIN
INSERT @Table (PersonId, SetLocation, Distance)
SELECT
@PersonId,
CASE WHEN PL.ID > 0 THEN 1 ELSE 0 END,
ISNULL(SQRT(((L.Gx - @Gx) / 10) * (L.Gx - @Gx) / 10 + ((L.Gy - @Gy) / 10) * (L.Gy - @Gy) / 10) / 10, 0)
FROM
Location L
LEFT JOIN PersonLocation PL ON L.ID = PL.LocationId AND PL.PersonId = @PersonId
WHERE
ISNULL(SQRT(((L.Gx - @Gx) / 10) * (L.Gx - @Gx) / 10 + ((L.Gy - @Gy) / 10) * (L.Gy - @Gy) / 10) / 10, 0) < 250
FETCH NEXT FROM Curs INTO @PersonId, @Gx, @Gy
END
CLOSE Curs
DEALLOCATE Curs
DROP TABLE Person
DROP TABLE Location
DROP TABLE PersonLocation
SELECT * FROM @Table
答案 0 :(得分:1)
这似乎给出了相同的结果。 Sql Fiddle here
WITH cte AS
(
SELECT
P.Id AS PersonId,
CASE WHEN PL.ID > 0 THEN 1 ELSE 0 END AS SetLocation,
ISNULL(SQRT(((L.Gx - P.Gx) / 10) * (L.Gx - P.Gx) / 10 + ((L.Gy - P.Gy) / 10) * (L.Gy - P.Gy) / 10) / 10, 0) AS Distance
FROM
Person P
CROSS JOIN Location L
LEFT JOIN PersonLocation PL
ON p.ID = PL.PersonID AND
L.ID = PL.LocationId
)
SELECT PersonId, SetLocation, Distance
FROM cte
WHERE Distance < 250;
基本上,cte用于来自你在光标中所做的连接的project
派生列,然后可以在过滤器,进一步连接等中使用投影列。光标具有交叉的效果在人员和位置之间加入,每人至少有一行,如果PersonLocation
中有多行,则可能更多。