通过多个表循环查询
Loop query through multiple tables
我想要同一个查询,它几乎不会 return 通过多个 table 获得任何结果。 table 名称是相同的,只是增加了年份。所以我的查询看起来像这样:
select p.productID, po.name, p.price from prices_2001 p
join products po on p.productID = po.id
where price < 0
我想遍历从 2001 年到 2020 年的所有年份。所以它应该是这样的:
select p.productID, po.name, p.price from prices_2001 p
join products po on p.productID = po.id
where price < 0
select p.productID, po.name, p.price from prices_2002 p
join products po on p.productID = po.id
where price < 0
select p.productID, po.name, p.price from prices_2003 p --Looping trough all the tables until 2020
join products po on p.productID = po.id
where price < 0
如果有结果,可以将它们存储在临时文件中 table。我想用 table 名称创建一个循环或创建动态 sql 查询。最佳做法是什么?如何仅通过执行一次就将此查询用于所有 table?
谢谢!
这很困难且代价高昂(循环 SQL 语句!)因为您的模式很糟糕。相反,您应该有一个与现有 table 相同的 table prices
,但多了一个名为 year
的列。然后加入就变得简单了,你不必仅仅因为日期改变就创建新的 tables。
相反,尽管您可以将 table 联合在一起并得到相同的结果。类似于:
SELECT p.productID, po.name, p.price, po.year
FROM products p
INNER JOIN
(
SELECT id, name, 2001 as year FROM prices_2001
UNION ALL SELECT id, name, 2002 FROM prices_2002
UNION ALL SELECT id, name, 2003 FROM prices_2003
UNION ALL ... <continue until you have all year tables accounted for>
) po
ON p.productID = po.id
WHERE po.price < 0;
考虑将 UNION 子查询的结果写入新的 table,并从现在开始使用它。
重申我的评论:
This sounds like a denormalisation problem, really you should have 1 table with a column for the year.
真的,你应该修复你的设计。
无论如何,进入问题:你可以用动态 SQL 来做到这一点,是的,但你最好修复设计。然而,这会动态创建和执行语句。由于缺少版本标签,我使用了 FOR XML PATH
:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET @SQL = STUFF((SELECT @CRLF + N'UNION ALL' + @CRLF +
N'SELECT p.productID, po.name, p.price' + @CRLF +
N'FROM ' + QUOTENAME(t.[name]) + N'p' + @CRLF +
N' JOIN product po ON p.productID = po.id' + @CRLF +
N'WHERE p.price < 0'
FROM sys.tables t
WHERE t.[name] LIKE N'prices[_]20[0-9][0-9]'
ORDER BY t.[name]
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,13,N'') + N';';
--PRINT @SQL; --Your debugging friend
EXEC sys.sp_executesql @SQL;
我想要同一个查询,它几乎不会 return 通过多个 table 获得任何结果。 table 名称是相同的,只是增加了年份。所以我的查询看起来像这样:
select p.productID, po.name, p.price from prices_2001 p
join products po on p.productID = po.id
where price < 0
我想遍历从 2001 年到 2020 年的所有年份。所以它应该是这样的:
select p.productID, po.name, p.price from prices_2001 p
join products po on p.productID = po.id
where price < 0
select p.productID, po.name, p.price from prices_2002 p
join products po on p.productID = po.id
where price < 0
select p.productID, po.name, p.price from prices_2003 p --Looping trough all the tables until 2020
join products po on p.productID = po.id
where price < 0
如果有结果,可以将它们存储在临时文件中 table。我想用 table 名称创建一个循环或创建动态 sql 查询。最佳做法是什么?如何仅通过执行一次就将此查询用于所有 table?
谢谢!
这很困难且代价高昂(循环 SQL 语句!)因为您的模式很糟糕。相反,您应该有一个与现有 table 相同的 table prices
,但多了一个名为 year
的列。然后加入就变得简单了,你不必仅仅因为日期改变就创建新的 tables。
相反,尽管您可以将 table 联合在一起并得到相同的结果。类似于:
SELECT p.productID, po.name, p.price, po.year
FROM products p
INNER JOIN
(
SELECT id, name, 2001 as year FROM prices_2001
UNION ALL SELECT id, name, 2002 FROM prices_2002
UNION ALL SELECT id, name, 2003 FROM prices_2003
UNION ALL ... <continue until you have all year tables accounted for>
) po
ON p.productID = po.id
WHERE po.price < 0;
考虑将 UNION 子查询的结果写入新的 table,并从现在开始使用它。
重申我的评论:
This sounds like a denormalisation problem, really you should have 1 table with a column for the year.
真的,你应该修复你的设计。
无论如何,进入问题:你可以用动态 SQL 来做到这一点,是的,但你最好修复设计。然而,这会动态创建和执行语句。由于缺少版本标签,我使用了 FOR XML PATH
:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET @SQL = STUFF((SELECT @CRLF + N'UNION ALL' + @CRLF +
N'SELECT p.productID, po.name, p.price' + @CRLF +
N'FROM ' + QUOTENAME(t.[name]) + N'p' + @CRLF +
N' JOIN product po ON p.productID = po.id' + @CRLF +
N'WHERE p.price < 0'
FROM sys.tables t
WHERE t.[name] LIKE N'prices[_]20[0-9][0-9]'
ORDER BY t.[name]
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,13,N'') + N';';
--PRINT @SQL; --Your debugging friend
EXEC sys.sp_executesql @SQL;