case when results as left join condition - sql

Table 1
Staff category hours cost
1 Cleaning 5 20
1 Scrubbing 6 30
1 Cleaning 8 40
2 Scrubbing 4 30
table 2
`
Staff type vendor category
1 part A Cleaning
1 full b Cleaning
1 full c Scrubbing
...’
To join these two tables I added a new col “type”:
Case when table1.hours=8
Then ”full”
Else ”part”
End as “type”
From table1
Left join table2 on type=table2.type
And Table 1.staff =table2.staff
And Table1.category=table 2.category
My desired outcome is
Staff category Cost vendor type
1 Cleaning 20 A. Part
1 Cleaning 40 B. Full
1 Scrubbing 30 C. Part
However the type=table2.type condition didn’t work so it became
Staff category Cost vendor type
1 Cleaning 20 A. Part
1 Cleaning 20 B. part
1 cleaning 40. A Full
1. Cleaning 40 B. Full

Below is for BigQuery Standard SQL
#standardSQL
SELECT staff, category, cost, vendor, type
FROM (
SELECT *, IF(hours = 8, 'full', 'part') AS type
FROM `project.dataset.table1`
) t1
LEFT JOIN `project.dataset.table2` t2
USING (type, staff, category)

If I have not understood, you want an implementation that creates a column in table1 and then joins with table2 on the condition table1.category = table2.category and table1.type = table2.type. If that's the case you could try with the following:
SELECT t1.Staff, t1.category, t1.cost, table2.vendor, t1.type
FROM (
SELECT *, CASE WHEN table1.hours = 8 THEN "full" ELSE "part" END as type
FROM table1
) t1
INNER JOIN table2
ON t1.category = table2.category
AND t1.type = table2.type
AND t1.staff = table2.staff

Related

Excel Grouping (or using SQL) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Believe I am overthinking this. So created a SQL report to generate data that looks like this:
Client# Parent# Industry Client Name A B C D E F G
1 0 Agriculture ABC Co. 0 0 0 50 0 0 0
2 1 Agriculture DEF Co. 25 0 0 0 0 0 0
3 2 Agriculture GHI Co. 0 0 0 0 0 0 75
There are like 10,000 rows. If you noticed, there is a client number and a parent number. The 3 results displayed above are sub companies that are all under the "ABC Co." business. What is the best way to group them all together into one line within an Excel report? Have the result look like this:
Client# Parent# Industry Client Name A B C D E F G Total
1 0 Agriculture ABC Co. 25 0 0 50 0 0 75 150
Was thinking possibilities being:
1) Customize SQL code to format the data to look the way I want it (would be nice bc every time I run the report, I would have to do minimal work after it collects the data). I understand though it is more appropriate to use SQL just to retreive the data.
2) There being an option within Excel to accomplish this.
3) Create a macro to sort through the data and format it the way I want.
Thank you for reading!
" So created a SQL report to generate data that looks like this:"
The reason for your downvotes is likely due to you not posting the SQL code here. Leaves me guessing at your table formats, so for my ease... select * from mytable is what I'll guess you've used. I'm left guessing column names too...in future questions, more information is helpful so I assume less.
select t1.client, t2.client, t3.client, t4.client, t1.parent, t2.parent, t3.parent, t1.*
from maytable t1
left join mytable t2 on t1.parent = t2.client
left join mytable t3 on t2.parent = t3.client
left join mytable t4 on t3.parent = t4.client
etc pending how deep this relation goes.
This will give you a list showing the parents. The t1.* is simply to grab the data columns related, you should write out your columns in full, I'm being lazy since no column list was supplied. The client IDs should look like this in your example (I've ignored parentID in my list below)
row 1 - 1 , 0, null , null
row 2 - 2 , 1 , 0, null
row 3 - 3 , 2 , 1, 0
Now we need a case statement...when the parent = 0 then show that client id.
select client_id, case when t1.parentid = 0 then t1.client_id
when t2.parentid = 0 then t2.client_id
when t3.parentid = 0 then t3.client_id
when t4.parentid = 0 then t4.clientID
end as parent_ID
, t1.*
from (same as above query)
You can take what was just written above and call it a sub query and select from it, this time grabbing the sums of the columns you want.
select parent_id, sum(a), sum(b), etc...
from
(select client_id, case when t1.parentid = 0 then t1.client_id
when t2.parentid = 0 then t2.client_id
when t3.parentid = 0 then t3.client_id
when t4.parentid = 0 then t4.clientID
end as parent_ID
, t1.*
from maytable t1
left join mytable t2 on t1.parent = t2.client
left join mytable t3 on t2.parent = t3.client
left join mytable t4 on t3.parent = t4.client
etc pending how deep this relation goes. ) a
group by parent_id
Unfortunately this is the best code I can provide with the limited info you've given.

I'm trying to do multiple left joins in SQL Server and I'm getting unexpected results when a value is not found in the table being joined

I am making a SQL query to find the products in a database that are below ROP(reorder point) and that belong to a specific production cell.
To do this I have to do several operations on my selected columns, and I have to join multiple tables.
Here is the SQL that I have written:
Select Statement
SELECT it.ItemID, descr.ShortDesc, CONVERT(INT,inv.OrderPoint) AS ROP,
CONVERT(INT, (bin.QtyOnHand - inv.QtyOnSO + inv.QtyOnPO)) AS Avail,
CONVERT(INT, bin.QtyOnHand) AS QOH, CONVERT(INT,inv.QtyOnSO) AS Sold,
CONVERT(INT,((bin.QtyOnHand - inv.QtyOnSO)/(sale.PrevYearQtySold/10)*100)) AS percentUsage,
CONVERT(INT, sale.PrevYearQtySold/10) AS moUsage, CONVERT(INT,inv.MaxStockQty) AS Bin,
CONVERT(INT, inv.OrderPoint - (bin.QtyOnHand - inv.QtyOnSO)) AS NTS
FROM timItem AS it
Table Joins
LEFT JOIN timInventory AS inv
ON it.ItemKey = inv.ItemKey
LEFT JOIN timItemClass AS itClass
ON it.ItemClassKey = itClass.ItemClassKey
LEFT JOIN timItemDescription AS descr
ON it.ItemKey = descr.ItemKey
LEFT JOIN texItemSalesSummary AS sale
ON it.ItemKey = sale.ItemKey
LEFT JOIN timWhseBinInvt AS bin
ON it.ItemKey = bin.ItemKey
Where Clause
WHERE (bin.QtyOnHand - inv.QtyOnSO) < inv.OrderPoint
AND itClass.ItemClassID = 'A'
ORDER BY
ORDER BY percentUsage ASC
sql with syntax highlighting
Upon the completion of my query I get something that looks like the following:
Item ID || ShortDesc || ROP || AVAIL || QOH || SOLD || %Usage || mo Use || Bin || NTS
item descr 12 -4 47 51 -8 46 24 16
item descr 6 0 12 12 0 11 12 6
item descr 18 0 44 44 0 9 20 18
This would be fine, minus the fact that if an item in the timWhseBinInvt has a temporary bin location and it's QtyOnHand reaches zero. It's row is automatically deleted from the table (just the way that our MAS500 schema browser describes it).
Thus leaving me with an incomplete result, excluding the items that don't exist in that particular table.
I would like to see data that looks more like this:
Item ID || ShortDesc || ROP || AVAIL || QOH || SOLD || %Usage || mo Use || Bin || NTS
item descr 12 -4 47 51 -8 46 24 16
item descr 6 null null 5 null 11 12 6
item descr 18 0 44 44 0 9 20 null
This would give me all of the items in the 'A' production cell, including items that aren't found in the table timWhseBinInvt. The columns corresponding with that table should have a value of null for the items that do not exist within that table.
From my research on different types of joins. it seemed that left joins make this kind of functionality possible.
I've also looked into *is null, not exists,*etc. with no luck.
I apologize if this post is unclear to anybody, I'm very new to writing SQL queries and I thought I'd reach out on here to see if anybody with more experience could help.
Thanks
Your where clause is turning the outer joins into inner joins. You need to move the conditions to the on clause. I suspect that you want to filter by class A, so this might do what you want:
FROM timItem it JOIN
timInventory inv
ON it.ItemKey = inv.ItemKey JOIN
timItemClass AS itClass
ON it.ItemClassKey = itClass.ItemClassKey LEFT JOIN
timItemDescription AS descr
ON it.ItemKey = descr.ItemKey LEFT JOIN
texItemSalesSummary AS sale
ON it.ItemKey = sale.ItemKey LEFT JOIN
timWhseBinInvt AS bin
ON it.ItemKey = bin.ItemKey AND
(bin.QtyOnHand - inv.QtyOnSO) < inv.OrderPoint
WHERE itClass.ItemClassID = 'A'
As stated in my Comment, putting a WHERE clause on a column which is from a table you have performed a LEFT JOIN on implicitly transforms the join to an INNER JOIN. For example the two following statements are the same (even though one uses a LEFT JOIN):
SELECT *
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T1.ID = T2.ID
WHERE T2.ID = 7;
SELECT *
FROM TABLE1 T1
JOIN TABLE2 T2 ON T1.ID = T2.ID
WHERE T2.ID = 7;
Instead, put the clause on the "left" table in your ON clause:
SELECT *
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T1.ID = T2.ID
AND T2.ID = 7;

Update a range of rows in a table where the condition is in another table

example:
table 1
invoice line article price
1 1 pen 10
1 2 mouse 11
1 3 paper 15
2 1 ... 25
2 2 ... 80
2 3 ...
2 4 ....
table 2
invoice date
1 2014-01-03 00:00:00.0000
2 2014-05-12 00:00:00.0000
3 2014-06-17 00:00:00.0000
how can I update the price only on the rows where the invoice date is for example the month of november
I know that i must use a join but i'm already joining this table for doing other stuff in the same query:
UPDATE invoicelines
SET invoicelines.netprice = ART.price
FROM invoicelines IL INNER JOIN items ITM
ON IL.item = ITM.item
i want to update the invoicelines with a specified date, but this date is in another table, and the situation is similar to the first example
update table1
set price = price + 10
from table1 t1 join table2 t2 on t1.invoice = t2.invoice
where month(t2.date) = 11
As to "I know that i must use a join": No, you don't have to join. When a condition is in another table you would usually use EXISTS or IN.
update table1
set price = ...
where invoice in
(
select invoice
from table2
where month(`date`) = 11
);
Or:
update table1
set price = ...
where exists
(
select *
from table2
where month(table2.`date`) = 11
and table2.invoice = table1.invoice
);
You forgot to name your dbms. Date functions are mostly dbms specific, so a MONTH function may be available or not.
I Solved With This
UPDATE Invoicelines
SET Invoicelines.NetPrice = ART.Price
FROM Invoicelines BR INNER JOIN Items ART join InvoiceHead bt on month(bt.docdate)=11
ON BR.Item = ART.Item
where BR.sheetNumber=bt.sheetNumber

T-SQL cursor or if or case when

I have this table:
Table_NAME_A:
quotid itration QStatus
--------------------------------
5329 1 Assigned
5329 2 Inreview
5329 3 sold
4329 1 sold
4329 2 sold
3214 1 assigned
3214 2 Inreview
Result output should look like this:
quotid itration QStatus
------------------------------
5329 3 sold
4329 2 sold
3214 2 Inreview
T-SQL query, so basically I want the data within "sold" status if not there then "inreview" if not there then "assigned" and also at the same time if "sold" or "inreview" or "assigned" has multiple iteration then i want the highest "iteration".
Please help me, thanks in advance :)
This is a prioritization query. One way to do this is with successive comparisons in a union all:
select a.*
from table_a a
where quote_status = 'sold'
union all
select a.*
from table_a a
where quote_status = 'Inreview' and
not exists (select 1 from table_a a2 where a2.quoteid = a.quoteid and a2.quotestatus = 'sold')
union all
select a.*
from table_a a
where quote_status = 'assigned' and
not exists (select 1
from table_a a2
where a2.quoteid = a.quoteid and a2.quotestatus in ('sold', 'Inreview')
);
For performance on a larger set of data, you would want an index on table_a(quoteid, quotestatus).
You want neither cursors nor if/then for this. Instead, you'll use a series of self-joins to get these results. I'll also use a CTE to simplify getting the max iteration at each step:
with StatusIterations As
(
SELECT quotID, MAX(itration) Iteration, QStatus
FROM table_NAME_A
GROUP BY quotID, QStats
)
select q.quotID, coalesce(sold.Iteration,rev.Iteration,asngd.Iteration) Iteration,
coalesce(sold.QStatus, rev.QStatus, asngd.QStatus) QStatus
from
--initial pass for list of quotes, to ensure every quote is included in the results
(select distinct quotID from table_NAME_A) q
--one additional pass for each possible status
left join StatusIterations sold on sold.quotID = q.quotID and sold.QStatus = 'sold'
left join StatusIterations rev on rev.quotID = q.quotID and rev.QStatus = 'Inreview'
left join StatusIterations asngd on asngd.quotID = q.quotID and asngd.QStatus = 'assigned'
If you have a table that equates a status with a numeric value, you can further improve on this:
Table: Status
QStatus Sequence
'Sold' 3
'Inreview' 2
'Assigned' 1
And the code becomes:
select t.quotID, MAX(t.itration) itration, t.QStatus
from
(
select t.quotID, MAX(s.Sequence) As Sequence
from table_NAME_A t
inner join Status s on s.QStatus = t.QStatus
group by t.quotID
) seq
inner join Status s on s.Sequence = seq.Sequence
inner join table_NAME_A t on t.quotID = seq.quotID and t.QStatus = s.QStatus
group by t.quoteID, t.QStatus
The above may look like complicated at first, but it can be faster and it will scale easily beyond three statuses without changing the code.

SQL select column equivalence

I have a table that saves the possible states of other tables (entities).
But now I need to find equivalence of states between two entities.
The table structure is something like this
ID TableID StateValue StateDefinition StateDescription
================================================================
1 1 1 Created Just created
2 1 2 Dropped Just Dropped
3 2 1 Created Just Created
4 2 2 Aproved Passed the revision
5 2 3 Dropped Just dropped
I want to get equivalent (comparing text of state) which as a result get this:
TableID1 StateValue1 TableID2 StateValue2 StateDefinition
=============================================================================
1 1 2 1 Created
1 2 2 3 Dropped
My question is, how can it be done??
Do a self join on the table.
A general case might look like:
SELECT A.TableID as TableId1,
A.StateValue as StateValue1,
B.TableId as TableId2,
B.StateValue as StateValue2,
A.StateDefinition
FROM
Table A
INNER JOIN Table B
ON (A.TableId <> B.TableId and A.StateDefiniton = B.StateDefinition)
select t1.TableID as TableID1,
t1.StateValue as StateValue1,
t2.TableID as TableID2,
t2.StateValue as StateValue2,
t1.StateDefinition
from MyTable t1
inner join MyTable t2 on t1.TableID = 1 and t2.TableID = 2
where t1.StateValue = t2.StateValue
and t1.StateDefinition = t2.StateDefinition