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 中使用的别名?
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
我有一个简单的 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 中使用的别名?
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