【问题标题】:Merge three tables in Select query by rule 3, 2, 1 records from each table在 Select query 中合并三个表,每个表中的规则 3、2、1 记录
【发布时间】:2019-03-09 08:58:56
【问题描述】:

Select 查询中按规则 3、2、1 合并每个表中的三个表,如下所示:

  • 表A:ID、字段A、字段B、字段C、....
  • 表 B:ID、字段A、字段B、字段C、....
  • TableC:ID、FieldA、FieldB、FieldC、....

  • ID:每张表自动编号

  • FieldA 在所有三个表中都是唯一的。

我正在寻找一个Select 查询来合并三个表,如下所示:

  • 来自TableA的前三条记录按ID排序
  • TableB 的前两条记录按 ID 排序
  • 来自TableC的前1条记录,按ID排序

重复此操作,直到从所有三个表中选择所有记录。

如果某些表的记录较少或不符合条件,请忽略该表并继续其他表。

我的尝试:

我完全是通过编程方式完成的,比如 SQL Server 存储过程中的游标和If 条件。

这会造成延迟。

【问题讨论】:

  • 到目前为止你有什么尝试?
  • @iminiki 制作一个 tmp 表,其中填充 1000 个 ID 或三个表的总数,然后使用 SQL 游标、While 循环、If 条件和变量填充 tmp 表并最后使用 select 查询
  • 您的进程是否接受光标。
  • 如果表格包含 7 行,那么您的输出应该是什么?
  • 表A,表A,表A,表B,表B,表C,表A,表A,表A,表B,表C,表A,表B,表B,表C,表B,表B,表C,表C,表C,,, ,

标签: sql sql-server


【解决方案1】:

这需要一个公式,该公式从每个表中获取行号并将其转换为一系列跳过所需值的整数。

在下面的查询中,为了缩短公式,我添加了一些 CTE。真正的魔力在于UNION。另外,我正在为您的控件添加一个附加字段。随意摆脱它。

WITH A_Aux as (
SELECT 'A' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableA.*
FROM TableA
), B_Aux AS (
SELECT 'B' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableB.*
FROM TableB
), C_Aux AS (
SELECT 'C' As FromTable, ROW_NUMBER() OVER (Order BY ID) AS RowNum, TableC.*
FROM TableC
)
SELECT *
FROM (
    SELECT RowNum+3*FLOOR((RowNum-1)/3) As ColumnForOrder, A_Aux.* FROM A_Aux
    UNION ALL
    SELECT 3+RowNum+4*FLOOR((RowNum-1)/2), B_Aux.* FROM B_Aux
    UNION ALL
    SELECT 6*RowNum, C_Aux.* FROM C_Aux
) T
ORDER BY ColumnForOrder

PS:注意Offset + RowNum + (6-N) * Floor((RowNum-1)/N) 将 N 条记录组合在一起的模式(对于TableC,它当然简化了很多)。

PPS:我手头没有 SQL 服务器来测试它。如果有语法错误,请告诉我。

【讨论】:

  • 到现在为止好多了。
【解决方案2】:

你可以试试这个..

    GO

    select * into #temp1 from (select  * from  table1) as t1
    select * into #temp2 from (select  * from  table2) as t2
    select * into #temp3 from (select  * from  table3) as t3

    select * into #final from (select col1, col2, col3 from #temp1 where 1=0) as tb

    declare @i int

    set @i=1
    while( (select COUNT(*) from #temp1)>@i)
    Begin

    ;with ct1 as (
    select ROW_NUMBER() over (order by id) as Slno, * from #temp1
    ),ct2 as (
    select ROW_NUMBER() over (order by id) as Slno, * from #temp2
    ),ct3 as (
    select ROW_NUMBER() over (order by id) as Slno, * from #temp3
    ),cfinal as (
    select top 3 * from #temp1
    union all
    select top 2 * from #temp2
    union  all
    select top 1 * from #temp3
    )
    insert into #final ( col1 , col2, col3 )
    select col1, col2, col3 from cfinal

    delete from #temp1 where id in (select top 3 ID from #temp1)
    delete from #temp2 where id in (select top 2 ID from #temp2)
    delete from #temp3 where id in (select top 1 ID from #temp3)

    set @i = @i+1

    End

    Select * from #final

    Drop table #temp1
    Drop table #temp2
    Drop table #temp3

    GO

首先为所有 3 个表创建临时表,每次插入删除插入的记录,如果我这边没有任何遗漏,这将为您带来所需的结果。 如果可行,请注意这一点。

【讨论】:

    【解决方案3】:

    这里没有太多信息可以参考,但我假设您可以使用 UNION 来组合多个语句。

    SELECT * TableA ORDER BY ID DESC OFFSET 3 ROWS 
    UNION
    SELECT * TableB ORDER BY ID DESC OFFSET 2 ROWS 
    UNION
    SELECT * TableC ORDER BY ID DESC OFFSET 1 ROWS 
    

    执行并查看是否有效。

    /AF

    【讨论】:

    • 这个问题是关于 (Microsoft) SQL Server - SQL Server 和 ANSI/ISO SQL 标准都不知道 LIMIT 运算符.....跨度>
    • 感谢您的来信! @marc_s
    【解决方案4】:

    据我了解,我创建了三个临时表,分别为 ta、tb、tc。

    select * into #ta from (
    select 'A' a
    union all
    select 'A' a
    union all
    select 'A' a
    union all
    select 'A' a
    union all
    select 'A' a
    union all
    select 'A' a
    union all
    select 'A' a
    ) a
    
    select * into #tb from (
    select 'B' b
    union all
    select 'B' 
    union all
    select 'B' 
    union all
    select 'B' 
    union all
    select 'B' 
    ) b
    
    select * into #tc from (
    select 'C' c
    union all
    select 'C' 
    union all
    select 'C' 
    union all
    select 'C' 
    union all
    select 'C' 
    ) c
    

    如果表与您的表匹配,则输出类似于 A,A,A,B,B,C,A,A,A,B,B,C,A,B,C,C,C

    T-SQL

    declare @TAC int = (select count (*) from #ta)      -- Table A Count = 7
    declare @TBC int = (select count (*) from #tb)      -- Table B Count = 5
    
    declare @TAR int = @TAC % 3                         -- Table A Reminder = 1  
    declare @TBR int = @TBC % 2                         -- Table B Reminder = 1 
    
    declare @TAQ int = (@TAC - @TAR) / 3                -- Table A Quotient = (7 - 1) / 3 = 2, is will passed on NTILE
                                                        -- So we gonna split as two group (111), (222)
    declare @TBQ int = (@TBC - @TBR) / 2                -- Table B Quotient = (5 - 1) / 2 = 2, is will passed on NTILE
                                                        -- So we gonna split as two group (11), (22)
    
    select * from (
     select *, NTILE (@TAQ) over ( order by a) FirstOrder, 1 SecondOrder from (
      select top (@TAC - @TAR) * from #ta order by a
     ) ta                                               -- 6 rows are obtained out of 7.
     union all 
     select *, @TAQ + 1, 1 from (
      select top (@TAR) * from #ta order by a desc
     ) ta                                               -- Remaining one row is obtained. Order by desc is must
                                                        -- Here FirstOrder is next value of previous value. 
     union all
    
     select *, NTILE (@TBQ) over ( order by b), 2  from (
      select top (@TBC - @TBR) * from #tb order by b
     ) tb                                               
     union all 
     select *, @TBQ + 1, 2 from (
      select top (@TBR) * from #tb order by b desc
     ) tb           
    
     union all 
    
     select *, ROW_NUMBER () over (order by c), 3 from #tc                                  
    ) abc order by FirstOrder, SecondOrder  
    

    让我解释一下 T-SQL: 在此之前,FYR:NTILERow Number

    1. 获取计数。
    2. 找到将传递给 NTILE 函数的商。
    3. 按 NTILE 值和静态排序。

    注意:

    1. 我使用的是 SQL Server 2017。
    2. 如果 T-SQL 工作正常,那么您需要更改 order by <yourcolumn> 中的列。

    【讨论】:

      猜你喜欢
      • 2014-05-28
      • 2021-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多