首页 > 解决方案 > 从表中为选择的每一行选择任意行

问题描述

SELECT 
    R.ArrivalAirportID, 
    (
        SELECT TOP(1) A1.AirportID 
        FROM Airport A1 
        WHERE A1.ISO_country = 'PT' 
        ORDER BY( NEWID())
    ) 'PT Aleatory Airport'
FROM Routes R WHERE (
    SELECT A2.ISO_country 
    FROM Airports A2 
    WHERE A2.AirportID = R.ArrivalAirportID
) != 'PT

这是我的 SELECT,我希望AirportID列中的随机 sPT Aleatory AirportAirportID对于 SELECT 的所有行总是相同的。

如何在 SELECT 中AirportID FROM Airport A1 WHERE A1.ISO_country = 'PT'为每个随机设置一个?R.ArrivalAirportID

标签: sqlsql-server

解决方案


您需要在子查询中使用外部引用,以确保它逐行执行,而不仅仅是一次。我认为这可能会做到这一点:

SELECT 
    R.ArrivalAirportID, 
    (
        SELECT TOP(1) A1.AirportID 
        FROM Airport A1 
        WHERE A1.ISO_country = 'PT' 
        AND AI.AirportID <> R.ArrivalAirportID
        ORDER BY( NEWID())
    ) 'PT Aleatory Airport'
FROM Routes R WHERE (
    SELECT A2.ISO_country 
    FROM Airports A2 
    WHERE A2.AirportID = R.ArrivalAirportID
) != 'PT';

由于R.ArrivalAirportID仅限于国家代码不是的机场PT,并且AI.AirportID仅限于国家代码为的机场PT,因此这两个 ID 永远不可能相等,所以这个附加谓词不会改变查询的含义,但会改变执行计划。

如果这不起作用,那么另一种方法是为随机罐中的每个机场分配一个连续的行号,然后为每个

WITH RandomAirports AS
(   
    SELECT  a.AirportID,
            RowNumber = ROW_NUMBER() OVER(ORDER BY a.AirportID)
    FROM    Airport AS a 
    WHERE   a.ISO_country = 'PT' 
)
SELECT  r.ArrivalAirportID,
        [PT Aleatory Airport] = ra.AirportID
FROM    Routes AS r
        INNER JOIN dbo.Airports AS a
            ON a.AirportID = r.ArrivalAirportID
        CROSS JOIN (SELECT COUNT(*) FROM RandomAirports) AS rm (RandomMax)
        LEFT JOIN RandomAirports AS ra
            ON r1.RowNumber = CEILING(RAND(CHECKSUM(NEWID())) * rm.RandomMax)
WHERE   a.ISO_country <> 'PT';

这里的关键是:

r1.RowNumber = CEILING(RAND(CHECKSUM(NEWID())) * rm.RandomMax)

这会生成一个介于 1 之间的随机数,无论有多少机场可供选择,因此将有效地随机选择一个。


推荐阅读