Всегда ли возможно преобразовать несколько пространственных выборок с помощью цикла while и переменных в один запрос без использования временных таблиц в sql? - PullRequest
0 голосов
/ 23 мая 2019

Эту проблему можно решить с помощью временной таблицы, однако, Я не хочу использовать временную таблицу или таблицу var , этот вопрос в основном для моих личных образовательных целей.

Я унаследовал следующий SQL:

DECLARE  @i int = 993

while @i <=1000
begin
declare @lat nvarchar(20)
select top 1 @lat = SUBSTRING(Address,0,CHARINDEX(',',Address,0)) from dbo.rent
    where id  = @i; 
declare @lon nvarchar(20)
select top 1 @lon = SUBSTRING(Address,CHARINDEX(',',Address)+1,LEN(Address)) from dbo.rent
    where id  = @i 


declare @p GEOGRAPHY =  GEOGRAPHY::STGeomFromText('POINT('+ @lat +' '+@lon+')', 4326)


select price/LivingArea sq_m, (price/LivingArea)/avg_sq_m, * from
(select     (sum(price)/sum(LivingArea)) avg_sq_m,  count(1) cnt, @i id from 
        (select  *, GEOGRAPHY::STGeomFromText('POINT('+ 
        convert(nvarchar(20), SUBSTRING(Address,0,CHARINDEX(',',Address,0)))+' '+
        convert( nvarchar(20), SUBSTRING(Address,CHARINDEX(',',Address)+1,LEN(Address)))+')', 4326)
            .STBuffer(500).STIntersects(@p) as [Intersects]
            from dbo.rent
            where Address is not null 
        ) s
    where [Intersects] = 1) prox
    inner join dbo.rent r on  prox.id = r.id
    set @i = @i+1
end

он используется для анализа цен на недвижимость за квадратный метр, которые находятся рядом, и сравнивает их, чтобы увидеть, какие из них дешевле ...

Проблема: механизм вызова должен быть перемещен с C# на SQL, и все запросы должны быть объединены в один результат (теперь вы получаете по одной строке на один во время выполнения), то есть @i и @p должен уйти и стать while id < x and id > y или каким-то волшебным образом соединиться,

процедура является урезанной версией реальной вещи, но, имея решение вышеописанного, у меня не возникнет проблем с тем, чтобы все это работало ...

Я придерживаюсь мнения, что любой механизм SQL с переменными и циклами может быть преобразован в один оператор SQL, поэтому возникает вопрос.

SqlFiddle

Ответы [ 2 ]

0 голосов
/ 27 июня 2019

Это может быть сделано, в данном конкретном случае «обнаружение», которое было необходимо, было умение выполнить JOIN с Point, например, возможность объединять таблицы по близости (еще один небольшой обман был объединять точки-строки дляфактические моменты, но это просто оптимизация).Как только это будет сделано, запрос может быть переписан следующим образом:

SELECT adds.Url,
adds.Price/adds.LivingArea Sqm,
(adds.Price/adds.LivingArea)/k1.sale1Avg ratio,
       *
   FROM
   (SELECT baseid,
          count(k1Rent.rentid) rent1kCount,
          sum(k1Rent.RperSqM)/(count(k1Rent.rentid)) AS rent1kAvgSqM,
          count(around1k.SaleId) sale1kCount,
          (sum(k1sale.price)/sum(k1Sale.LivingArea)) sale1Avg,
          (sum(k1sale.price)/sum(k1Sale.LivingArea))/((sum(k1Rent.RperSqM)/(count(k1Rent.rentid)))*12) years --*
FROM
     (SELECT sa.id baseid,
             s.id saleid,
             s.RoomCount,
             POINT
      FROM SpatialAnalysis sa
      INNER JOIN Sale s ON s.Id = SaleId
      WHERE sa.SalesIn1kRadiusCount IS NULL) AS base
   JOIN SpatialAnalysis around1k ON base.Point.STBuffer(1000).STIntersects(around1k.Point) = 1
   LEFT OUTER JOIN
     (SELECT id rentid,
             rc,
             Price/avgRoomSize RperSqM
      FROM
        (SELECT *
         FROM
           (SELECT rc,
                   sum(avgArea*c)/sum(c) avgRoomSize
            FROM
              (SELECT roomcount rc,
                      avg(livingarea) avgArea,
                      count(1) c
               FROM Rent
               WHERE url LIKE '%systemname%'
                 AND LivingArea IS NOT NULL
               GROUP BY RoomCount
               UNION
                 (SELECT roomcount rc,
                         avg(livingarea) avgArea,
                         count(1) c
                  FROM sale
                  WHERE url LIKE '%systemname%'
                    AND LivingArea IS NOT NULL
                  GROUP BY RoomCount))uni
            GROUP BY rc) avgRoom) avgrents
      JOIN rent r ON r.RoomCount = avgrents.rc) k1Rent ON k1Rent.rentid =around1k.RentId
   AND base.RoomCount = k1Rent.rc
   LEFT OUTER JOIN Sale k1Sale ON k1Sale.Id = around1k.SaleId
   AND base.RoomCount = k1Sale.RoomCount
   GROUP BY baseid) k1
 left outer join SpatialAnalysis sp on sp.Id = baseid
 left outer join Sale adds on adds.Id = sp.SaleId
 where adds.Price < 250000
 order by  years, ratio
0 голосов
/ 23 мая 2019

Если я правильно понимаю ваш вопрос (уберите необходимость в циклах и верните один набор данных), тогда вы можете использовать CTE (общие табличные выражения) для переменных Lats, Lons и Geog.

Вы; SQLFIddle ссылался на базу данных с именем "webanalyser", поэтому я удалил ее из запроса ниже

Однако запрос ничего не даст, так как в данных примера содержатся неверные данные для столбца адреса.

;WITH cteLatsLongs
AS(
    SELECT
         lat    = SUBSTRING(Address, 0, CHARINDEX(',', Address, 0))
        ,lon    = SUBSTRING(Address, CHARINDEX(',', Address) + 1, LEN(Address))
    FROM dbo.rent
)
,cteGeogs
AS(
    SELECT
        Geog = GEOGRAPHY ::STGeomFromText('POINT(' + LL.lat + ' ' + LL.lon + ')', 4326)
    FROM cteLatsLongs LL
),cteIntersects
AS(
    SELECT *, 
            GEOGRAPHY::STGeomFromText('POINT(' + CONVERT(NVARCHAR(20), SUBSTRING(Address, 0, CHARINDEX(',', Address, 0))) + ' ' + CONVERT(NVARCHAR(20), SUBSTRING(Address, CHARINDEX(',', Address) + 1, LEN(Address))) + ')', 4326).STBuffer(500).STIntersects(G.Geog) AS [Intersects]
    FROM dbo.rent
    CROSS APPLY cteGeogs G
)
    SELECT avg_sq_m = (SUM(price) / SUM(LivingArea)), COUNT(1) cnt
    FROM
        cteIntersects I
    WHERE I.[Intersects] = 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...