The two tables are quite large and my select statement has more values than I get, but I think I can simplify this data and query in order to answer my question.
This is my select statement:
SELECT invoice.InvoiceNum, Layer, InvoiceItemNum FROM (INVOICE left outer join InvoiceItem item ON item.InvoiceNum = Invoice.InvoiceNum ) ORDER BY invoice.InvoiceNum
So I have two tables. Invoice table and InvoiceItem table. They are joined by the InvoiceNum column in each table and display the InvoiceNum and Layer columns
The following are the results of this query:
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
Since my InvoiceItem table has multiple rows that can be assigned to 1 InvoiceNum, this results in duplicate InvoiceNums in my results, which I don't want.
This is the result I am trying to get, to list only 1 invoice number from the invoice table, where the first case is a non-zero value from the layer column of the InvoiceItem table, and if there is no non-zero value, list The first zero.
Try something like this:
InvoiceNum | Layer | InvoiceItemNum 1 | 10 | 1 2 | 3 | 2 3 | 0 | 1 4 | 5 | 3
I'm just not sure how to do this, or if it's even possible given that they are on two different tables.
P粉3109311982024-02-22 12:26:01
Assumption/Understanding:
sybase
, the question does not differentiate between the 4x different Sybase RDBMS products (ASE
, SQLAnywhere
, IQ
, Advantage
), so I'll stick with common SQL syntax (i.e. 4x products have different SQL dialects; also, ASE doesn't support CTE)left (outer) join
as the output provided does not seem to indicate that there are any "missing" rows in InvoiceItem
Layer
and InvoiceItemNum
columns belong to, so I'm assuming they belong to InvoiceItem
Guess a set of minimal table definitions and associated insert
statements:
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)
Query that generates OP’s current output:
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
A few different (complex, confusing) ideas for generating the output the OP needs:
-- 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
Both of these will generate:
InvoiceNum Layer InvoiceItemNum ----------- ----------- -------------- 1 10 1 2 3 2 3 0 1 4 5 3
Comments:
left (external) join
ASE 16.0
P粉5510842952024-02-22 10:50:28
This question is a bit tricky:
Try it in 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
In MySQL 8:
Try this:
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 )