sql - 跨多个表选择 TOP 1000

标签 sql sql-server

我有一个数据库,每天都会在其中创建一个新表并填充数据(我知道这并不理想,但我无法更改它)。每个表的格式为“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
;

如有任何帮助,我们将不胜感激。

最佳答案

使用动态 SQL 的存储过程是解决此类问题的一个很酷的方法。在内存中创建一个数字表,使用它来创建您的 UNIONed super 表,然后执行动态 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;

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

关于sql - 跨多个表选择 TOP 1000,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74167020/

相关文章:

SQL - MIN 和 COUNT 的组合

php - 将表从 MySQL 同步到 MSSQL

c# - 如何从 SQL Server 向 c# 控制台应用程序发出信号?

php - 在特定时间段后从数据库表中删除一行

sql - 文件中的日期格式转换 'YYYYMMDD' TO 'MM/DD/YYYY'

php - 从 textarea 插入数据时需要在查询中转义什么?

sql - 无法识别指定的设置 'INSTALL'。错误代码 0x84B40003

sql-server - 医生排类数据库设计

sql-server - 使用 CATALOG_COLLATION 创建表失败并出现语法错误(将 Azure 数据库复制到本地开发 SQL Server)

c# - 可以在单个 SqlDataSource 中使用两种不同类型的数据库吗?