sql-server 跨多个表选择TOP1000 [已关闭]

5anewei6  于 2022-10-31  发布在  其他
关注(0)|答案(2)|浏览(85)

已关闭。此问题需要details or clarity。当前不接受答案。
**想要改进此问题吗?**通过editing this post添加详细信息并阐明问题。

6天前关闭。
这篇文章是4天前编辑并提交审查的。
Improve this question
我有一个数据库,我每天都会创建一个新表,并在其中填充数据(我知道这并不理想,但我无法更改)。每个表的格式都是“TESTdata_xxxxx_DB”,其中xxxxx每天递增1。
我需要一种简单的方法来选择这些表中的许多表(即,跨许多日期)的前1000行(满足特定条件的行)。例如,我需要跨表TESTdata_45800_DB、TESTdata_45801、...、TESTdata_45850_DB查询。
我已经尝试了下面的查询,但是很明显添加“to”不起作用,并且用逗号分隔它们也不能按照我想要的方式合并它们:

SELECT TOP 1000 
    [ItemIndex],
    [Data1],
    [Data2],
    [Data3]     
FROM 
    [TESTDB1].[dbo].[TESTdata_45800_DB] (to...) [TESTdata_45850_DB]
WHERE 
    Data1 LIKE 'High' OR Data1 LIKE 'Medium'
ORDER BY 
    Data1
;

任何帮助都将不胜感激。

tf7tbtn2

tf7tbtn21#

使用动态SQL的存储过程是解决这类问题的一种很好的方法。在内存中创建一个数字表,用它来创建UNIONE超表,然后执行动态SQL以获得所需的结果:

CREATE PROCEDURE [dbo].[Top1000]
(
    @startDatabaseNumber INT,
    @endDatabaseNumber INT
)
AS
SET NOCOUNT ON

-- inspired by https://stackoverflow.com/a/33146869/7806251
DECLARE @digits TABLE(d INT)
INSERT INTO @digits 
    SELECT 
        d
    FROM 
        (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(d)

DECLARE @numbers TABLE(DatabaseNumber VARCHAR(5))       
INSERT INTO @numbers
        SELECT
            LEFT('00000', 5 - LEN(n)) + n AS DatabaseNumber
        FROM
            (
            SELECT 
                CAST(
                    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)
                    ) AS VARCHAR(10)
                ) AS n
            FROM 
                @digits ones, 
                @digits tens, 
                @digits hundreds,
                @digits thousands,
                @digits tenthousands
            ) x
        WHERE
            n BETWEEN @startDatabaseNumber AND @endDatabaseNumber

DECLARE @unionedTable VARCHAR(MAX) = (      
    SELECT
        STRING_AGG(
            CAST(
                '(
                    SELECT
                        ItemIndex,
                        Data1,
                        Data2,
                        Data3
                    FROM
                        [TESTDB1].[dbo].[TESTdata_'+DatabaseNumber+'_DB]
                )'
            AS VARCHAR(MAX)) -- circumvents STRING_AGG() 8000 character constraint
        , ' UNION ALL ') -- just UNION if you want to de-dupe
    FROM
        @numbers
    )

DECLARE @sql NVARCHAR(MAX) = '
    SELECT TOP 1000 
        *
    FROM 
        ('+@unionedTable+') UnionedTable
    WHERE 
        Data1 IN (''High'', ''Medium'')
    ORDER BY 
        Data1
    ;
    '

-- PRINT @sql -- if you need to debug
EXECUTE sp_executesql @sql

一旦运行并存在了它,就可以用你喜欢的起始和结束数字来调用它:

EXEC Top1000 5, 15;

最后,正如其他评论者所表达的那样,我建议不要每天都创建一个新表,如果你可以帮助它的话。将每天的数据插入到一个正在运行的表中是更自然、更好的做法。

qyswt5oh

qyswt5oh2#

如果你想要一个表的联合,意味着所有表的所有行都被转储到一个行集中,那么就使用SQL UNION。

SELECT TOP (1000) [ItemIndex],[Data1],[Data2],[Data3]
 from 
   (select [Data1],[Data2],[Data3]
   FROM [TESTDB1].[dbo].[TESTdata_00005_DB] 
   )      
 UNION          
   (select [Data1],[Data2],[Data3]
   FROM [TESTDB1].[dbo].[TESTdata_00006_DB] 
   )      
  UNION
   (select [Data1],[Data2],[Data3]
   FROM [TESTDB1].[dbo].[TESTdata_00007_DB] 
   )      
 WHERE Data1 like 'High' OR Data1 like 'Medium'
  ORDER BY Data1

顺便说一句,虽然UNION工作得很好,但它的性能并不好,而且根据我的经验,从长远来看,做一堆联合可能会变得很难支持。在某个时候,您可能会考虑使用替代的数据架构,如具有多个分区的单个表,每天一个分区。

相关问题