SQL 查询:遍历 table 中的值并在子查询中使用它们

SQL query: Iterate over values in table and use them in subquery

我有一个简单的 SQL table 包含一些值,例如:

id | value    (table 'values')
----------
0  | 4
1  | 7
2  | 9

我想遍历这些值,并像这样在查询中使用它们:

SELECT value[0], x1
FROM (some subquery where value[0] is used)

UNION

SELECT value[1], x2
FROM (some subquery where value[1] is used) 

...
etc

为了获得这样的结果集:

4 | x1
7 | x2
9 | x3

它必须在 SQL 中,因为它实际上代表一个数据库视图。当然真正的查询要复杂很多,但是我尽量在保留本质的情况下简化问题。

我想我必须从 values select 并加入子查询,但由于该值应该在子查询中使用,我不知道如何完成这个。

编辑: 我把问题简单化了;实际上我想从子查询中得到 2 行,而不是只有 1 行。

编辑 2: 按照建议,我发布了真实的查询。我对其进行了一些简化以使其更清晰,但这是一个有效的查询,问题就在那里。请注意,我在此查询中对值“2”进行了两次硬编码。我想用来自不同 table 的值替换它,在上面的示例 table 中,我想要一个包含 4、7 和 9 作为值而不是当前查询的组合结果的结果集硬编码 2.

SELECT x.fantasycoach_id, SUM(round_points)
FROM (
    SELECT DISTINCT fc.id AS fantasycoach_id,
        ffv.formation_id AS formation_id,
        fpc.round_sequence AS round_sequence,
        round_points,
        fpc.fantasyplayer_id
    FROM fantasyworld_FantasyCoach AS fc

    LEFT JOIN fantasyworld_fantasyformation AS ff ON ff.id = (
            SELECT MAX(fantasyworld_fantasyformationvalidity.formation_id)
            FROM fantasyworld_fantasyformationvalidity
            LEFT JOIN realworld_round AS _rr ON _rr.id = round_id
            LEFT JOIN fantasyworld_fantasyformation AS _ff ON _ff.id = formation_id
            WHERE is_valid = TRUE
                AND _ff.coach_id = fc.id
                AND _rr.sequence <= 2 /* HARDCODED USE OF VALUE */
            )
    LEFT JOIN fantasyworld_FantasyFormationPlayer AS ffp 
    ON ffp.formation_id = ff.id

    LEFT JOIN dbcache_fantasyplayercache AS fpc 
    ON ffp.player_id = fpc.fantasyplayer_id
    AND fpc.round_sequence = 2 /* HARDCODED USE OF VALUE */

    LEFT JOIN fantasyworld_fantasyformationvalidity AS ffv 
    ON ffv.formation_id = ff.id
) x
GROUP BY fantasycoach_id

编辑 3: 我正在使用 PostgreSQL。

SQL和table是一个整体,基本就是集合运算。没有明确的迭代,通常不需要任何迭代。特别是,您所描述的最直接的实现是这样的:

SELECT value, (some subquery where value is used) AS x
FROM values

但是请注意,诸如此类的相关子查询对查询性能非常不利。根据您尝试执行的操作的详细信息,很可能围绕简单的连接、不相关的子查询或类似的、性能更好的替代方案来构建它。


更新:

鉴于问题的更新表明子查询预计会为 table values 中的每个值生成多行,与示例结果相反,似乎更好的方法是只是将子查询重写为主查询。如果它还没有这样做(也许即使这样做了),那么它将加入 table values 作为另一个基地 table.


更新二:

鉴于现在呈现的真实查询,table values 中的值可以这样合并到其中:

SELECT x.fantasycoach_id, SUM(round_points) FROM
(
    SELECT DISTINCT
        fc.id AS fantasycoach_id, 
        ffv.formation_id AS formation_id, 
        fpc.round_sequence AS round_sequence,
        round_points,
        fpc.fantasyplayer_id

    FROM fantasyworld_FantasyCoach AS fc
    -- one row for each combination of coach and value:
    CROSS JOIN values

    LEFT JOIN fantasyworld_fantasyformation AS ff
    ON ff.id = (
        SELECT MAX(fantasyworld_fantasyformationvalidity.formation_id)
        FROM fantasyworld_fantasyformationvalidity

        LEFT JOIN realworld_round AS _rr
        ON _rr.id = round_id

        LEFT JOIN fantasyworld_fantasyformation AS _ff
        ON _ff.id = formation_id

        WHERE is_valid = TRUE
        AND _ff.coach_id = fc.id

        -- use the value obtained from values:
        AND _rr.sequence <= values.value
    )

    LEFT JOIN fantasyworld_FantasyFormationPlayer AS ffp
    ON ffp.formation_id = ff.id

    LEFT JOIN dbcache_fantasyplayercache AS fpc
    ON ffp.player_id = fpc.fantasyplayer_id

    -- use the value obtained from values again:
    AND fpc.round_sequence = values.value

    LEFT JOIN fantasyworld_fantasyformationvalidity AS ffv
    ON ffv.formation_id = ff.id
) x
GROUP BY fantasycoach_id

请特别注意 CROSS JOIN,它形成两个 table 的叉积;这与没有任何连接谓词的 INNER JOIN 是一样的,如果需要可以这样写。

整体查询至少可以简化一点,但我没有这样做,因为它是一个工作示例而不是实际的生产查询,因此不清楚还有哪些其他更改会转化为实际应用程序。

在示例中,我创建了两个 table。看看外部 table 如何有一个你在内部 select 中使用的别名?

SQL Fiddle Demo

SELECT T.[value], (SELECT [property] FROM Table2 P WHERE P.[value] = T.[value])
FROM Table1 T 

这是提高性能的更好方法

SELECT T.[value], P.[property]
FROM Table1 T 
INNER JOIN Table2 p
   on P.[value] = T.[value];

Table 2 可以是 QUERY 而不是真正的 table

第三个选项

使用 cte 计算您的值,然后返回主 table。这样您就可以将子查询逻辑与最终查询分开。

WITH cte AS (
    SELECT 
        T.[value],
        T.[value] * T.[value] as property
    FROM Table1 T 
)
SELECT T.[value], C.[property]
FROM Table1 T 
INNER JOIN cte C
   on T.[value] = C.[value];

将计算提取到在 SELECT 子句中调用并针对结果集的每一行执行的函数中可能会有所帮助

这是 SQL 服务器的 CREATE FUNCTION 文档。它可能类似于您正在使用的任何数据库系统,如果不是,您可以轻松 Google 获取它。

下面是创建函数并在查询中使用它的示例:

CREATE FUNCTION DoComputation(@parameter1 int)
RETURNS int
AS
BEGIN
   -- Do some calculations here and return the function result.
   -- This example returns the value of @parameter1 squared.
   -- You can add additional parameters to the function definition if needed

   DECLARE @Result int
   SET @Result = @parameter1 * @parameter1

   RETURN @Result
END

这是在查询中使用上述示例函数的示例。

SELECT v.value, DoComputation(v.value) as ComputedValue
FROM [Values] v
ORDER BY value