这两个表相当大,我的 select 语句有更多我获得的值,但我认为我可以简化这些数据和查询,以便回答我的问题。
这是我的选择语句:
SELECT invoice.InvoiceNum, Layer, InvoiceItemNum FROM (INVOICE left outer join InvoiceItem item ON item.InvoiceNum = Invoice.InvoiceNum ) ORDER BY invoice.InvoiceNum
所以我有两张桌子。 Invoice 表和 InvoiceItem 表。它们由每个表中的 InvoiceNum 列连接起来,并显示 InvoiceNum 和 Layer 列
以下是此查询的结果:
InvoiceNum | Layer | InvoiceItemNum 1 | 10 | 1 1 | 0 | 2 1 | 7 | 3 1 | 0 | 4 2 | 0 | 1 2 | 3 | 2 3 | 0 | 1 3 | 0 | 2 3 | 0 | 3 4 | 0 | 1 4 | 0 | 2 4 | 5 | 3
由于我的 InvoiceItem 表有多行可以分配给 1 个 InvoiceNum,这导致我的结果中出现重复的 InvoiceNum,这是我不希望的。
这是我试图获得的结果,仅列出发票表中的 1 个发票编号,其中第一种情况是来自 InvoiceItem 表的图层列的非零值,如果没有非零值,则列出第一个零。
尝试这样的事情:
InvoiceNum | Layer | InvoiceItemNum 1 | 10 | 1 2 | 3 | 2 3 | 0 | 1 4 | 5 | 3
我只是不确定如何执行此操作,或者鉴于它们位于两个不同的表上,这是否可能。
P粉3109311982024-02-22 12:26:01
假设/理解:
sybase
标记,但问题并没有区分 4x 不同的 Sybase RDBMS 产品(ASE
、SQLAnywhere
、IQ
、Advantage
),因此我将坚持使用通用 SQL 语法(即 4x 产品具有不同的SQL 方言;此外,ASE 不支持 CTE)left (outer) join
的使用,因为提供的输出似乎没有表明 InvoiceItem
中存在任何“缺失”行Layer
和 InvoiceItemNum
列属于哪个表,因此我假设它们属于 InvoiceItem
猜测一组最小表定义和关联的 insert
语句:
create table Invoice (InvoiceNum int ) create table InvoiceItem (InvoiceNum int ,InvoiceItemNum int ,Layer int ) insert Invoice select 1 union all select 2 union all select 3 union all select 4 insert InvoiceItem values (1,1,10) insert InvoiceItem values (1,2,0) insert InvoiceItem values (1,3,7) insert InvoiceItem values (1,4,0) insert InvoiceItem values (2,1,0) insert InvoiceItem values (2,2,3) insert InvoiceItem values (3,1,0) insert InvoiceItem values (3,2,0) insert InvoiceItem values (3,3,0) insert InvoiceItem values (4,1,0) insert InvoiceItem values (4,2,0) insert InvoiceItem values (4,3,5)
生成OP当前输出的查询:
select inv.InvoiceNum, item.Layer, item.InvoiceItemNum from Invoice inv left -- superfluous in this case? join InvoiceItem item on inv.InvoiceNum = item.InvoiceNum order by 1,3 InvoiceNum Layer InvoiceItemNum ----------- ----------- -------------- 1 10 1 1 0 2 1 7 3 1 0 4 2 0 1 2 3 2 3 0 1 3 0 2 3 0 3 4 0 1 4 0 2 4 5 3
生成 OP 所需输出的几个不同(复杂、混乱)的想法:
-- join based on Layer!=0; if no rows found then override NULLs -- with Layer=0 and InvoiceItemNum=min(InvoiceItemNum) where Layer=0; -- needs more work in case there are no matching rows in InvoiceItem ... -- wrap case/then in a coalesce() and set to, what, 0? select inv.InvoiceNum, coalesce(item1.Layer,0) as "Layer", case when item1.InvoiceItemNum is NULL then (select min(InvoiceItemNum) from InvoiceItem item3 where item3.InvoiceNum = inv.InvoiceNum) else item1.InvoiceItemNum end as "InvoiceItemNum" from Invoice inv left join InvoiceItem item1 on inv.InvoiceNum = item1.InvoiceNum and item1.Layer != 0 and not exists(select 1 from InvoiceItem item2 where item2.InvoiceNum = item1.InvoiceNum and item2.Layer != 0 and item2.InvoiceItemNum < item1.InvoiceItemNum) order by 1 -- OR -- perform a mutually exclusive UNION of Layer!=0 and Layer=0 queries -- with Layer!=0 having prcedence select inv.InvoiceNum, item1.Layer, item1.InvoiceItemNum from Invoice inv --left ??? needs work if this is really an outer join ??? join InvoiceItem item1 on inv.InvoiceNum = item1.InvoiceNum and ( ( item1.Layer != 0 and not exists(select 1 from InvoiceItem item2 where item2.InvoiceNum = item1.InvoiceNum and item2.Layer != 0 and item2.InvoiceItemNum < item1.InvoiceItemNum) ) or ( item1.Layer = 0 and not exists(select 1 from InvoiceItem item3 where item3.InvoiceNum = item1.InvoiceNum and item3.Layer != 0) and not exists(select 1 from InvoiceItem item4 where item4.InvoiceNum = item1.InvoiceNum and item4.Layer = 0 and item4.InvoiceItemNum < item1.InvoiceItemNum) ) ) order by 1
这两者都会生成:
InvoiceNum Layer InvoiceItemNum ----------- ----------- -------------- 1 10 1 2 3 2 3 0 1 4 5 3
注释:
left (外部)join
ASE 16.0
中测试的所有查询P粉5510842952024-02-22 10:50:28
这个问题有点棘手:
在 Postgres 中尝试一下:
with cte as ( select inv.invoicenum,sum(layer::int) "sum_layer" from invoice inv inner join invoiceitem item on item.invoicenum=inv.invoicenum group by 1 ) , cte1 as ( select distinct on (inv.invoicenum) inv.invoicenum,layer, InvoiceItemNum from invoice inv inner join invoiceitem item on item.invoicenum=inv.invoicenum where inv.invoicenum in (select invoicenum from cte where sum_layer=0) order by inv.invoicenum, InvoiceItemNum ), cte2 as ( select distinct on (inv.invoicenum) inv.invoicenum, layer , InvoiceItemNum from invoice inv inner join invoiceitem item on item.invoicenum=inv.invoicenum where inv.invoicenum in (select invoicenum from cte where sum_layer>0) and layer::int>0 order by inv.invoicenum, InvoiceItemNum ) ( select * from cte1 union all select * from cte2 ) order by 1
在 MySQL 8 中:
试试这个:
with cte as ( select inv.invoicenum,sum(layer) "sum_layer" from invoice inv inner join invoiceitem item on item.invoicenum=inv.invoicenum group by 1 ) , cte1 as ( select * from ( select inv.invoicenum, layer, InvoiceItemNum from invoice inv inner join invoiceitem item on item.invoicenum=inv.invoicenum where inv.invoicenum in (select invoicenum from cte where sum_layer=0) order by inv.invoicenum, InvoiceItemNum ) c group by invoicenum ), cte2 as ( select * from ( select inv.invoicenum, layer, InvoiceItemNum from invoice inv inner join invoiceitem item on item.invoicenum=inv.invoicenum where inv.invoicenum in (select invoicenum from cte where sum_layer>0) and layer>0 order by inv.invoicenum, InvoiceItemNum ) c group by invoicenum ) ( select * from cte1 union all select * from cte2 )