SQL nested Inner Joins? Or Where Clause On Inner Joins? - sql

I am having an issue with a query I am trying to write. Unfortunately I can only query against the database and cannot change the schema. Here are some simplified example tables:
Table 1
itemID sale date
----------------------------
1 1/2015
1 3/2016
2 5/2016
2 1/2015
Table 2
itemID colorID price
--------------------------------------
1 1 23
1 2 10
1 3 13
2 1 11
2 2 14
2 3 18
Table 3
ColorID color
---------------------------------------
1 Red
2 Blue
3 Green
Table 4
SaleBegin SaleEnd ColorID
----------------------------------------
1/1/2014 12/31/2014 1
1/1/2015 12/31/2015 2
1/1/2016 12/31/2016 3
Now I need a query that essentially gets the price and color for both item ids in the first table. I'm not sure how to do it with this schema even just for one. I tried something like:
SELECT item_id, price, color FROM Table1 T1
INNER JOIN Table2 T2
ON T1.ItemID=T2.ItemID
INNER JOIN Table3 T3
ON T2.ColorID=T3.ColorID
INNER JOIN Table4 T4
ON T3.ColorID=T4.ColorID
WHERE T1.itemID between SaleBegin AND SaleEnd
But it's not working for me, instead giving me every possible color and price for each item. What am I doing wrong? How do I get those values? Expected results should look like:
itemID color price
------------------------------------
1 Blue 10
1 Green 13
2 Green 18
2 Blue 14

http://sqlfiddle.com/#!9/e6fac/4
SELECT t1.itemID
, t3.color
, t2.price
FROM table_1 t1
LEFT JOIN table_2 t2
ON t1.itemID = t2.itemID
LEFT JOIN table_3 t3
ON t2.colorID = t3.colorID
LEFT JOIN table_4 t4
ON t3.colorID = t4.colorID
WHERE t1.sale_date BETWEEN saleBegin and saleEnd;

I'm not sure this is what you're looking for, but this query will give you the itemID, color and price for each product during each sale
SELECT
t4.SaleBegin
,t4.SaleEnd
,t1.itemID
,t3.color
,t2.price
FROM Table4 t4
INNER JOIN Table1 t1
ON t4.SaleBegin = CAST(REPLACE(t1.[sale date], '/', '/1/') AS DATE)
INNER JOIN Table2 t2
ON t1.itemID = t2.itemID
AND t4.ColorID = t2.ColorID
INNER JOIN Table3 t3
ON t4.ColorID = t3.colorID
Here is the SQL Fiddle

Related

SQL Server : select from multiple tables and calculate percentages

I have four tables and I would need to extract data from them to calculate the percentage
Table1
ID FK1 FK2
------------------
1 1 1
2 2 2
3 3 3
Table2
ID Name
------------------
1 L1
2 A1
3 B
Table3
ID FK3
------------------
1 1
2 2
3 3
Table4
ID Name
------------------
1 BA
2 N
3 CE
Now I need to get a Name from table4, which will be displayed as individual rows and then a Name from table2, which will be listed as individual columns and the value will then be a percentage of the record from table4:
Name L1 A1 B
---------------------------
BA 20(%) 40(%) 40(%)
N 30(%) 20(%) 30(%)
CE 15(%) 15(%) 70(%)
Because there are links, I'll give an example of what question I have now
select t3.Name
from table1 t1 (nolock)
join table2 t2 (nolock) on t1.FK1 = t2.ID
join table3 t3 (nolock) on t1.FK2 = t3.ID
join table4 t4 (nolock) on t2.FK3 = t4.ID
Does anyone have any idea how to do this? Thank you very much

Joining results from 3 tables with same date

I have 3 tables like this:
table1
ID Date Number City
--------------------------------
1 18.11.2019 345 Bristol
table2
ID Date Type Code
-------------------------------
3 18.11.2019 returned 11
table3
ID Date Source Product
----------------------------------
39 18.11.2019 unknown shirt
I would like to write a query that shows a result for the same date on all three tables.
Desired result:
Date table1_Number table1_City table2_Type table2_Code table3_Source table3_Product
18.11.2019 345 Bristol returned 11 unknown shirt
Are you looking for simple joins, as follows?
select
t1.number table1_number,
t1.city table1_city,
t2.type table2_type,
t2.code table2_code,
t3.source table3_source,
t3.product table3_product
from table1 t1
inner join table2 t2 on t1.date = t.date
inner join table3 t3 on t3.date = t.date

Joining tables without nulls

I'm not sure how to explain what I need but here's the data first:
Table 1
District
-1
3
2
1
3
Table 2
ID ID_Name
1 Main 1
2 Main 2
3 Main 3
How do I join the tables so that it looks like this?
District
-1
Main 3
Main 2
Main 1
Main 3
I'm assuming the second column is named Name for this, but you can do it with a COALESCE and a LEFT JOIN:
Select Coalesce(T2.Name, Str(T1.District)) As District
From Table1 T1
Left Join Table2 T2 On T1.District = T2.Id
assuming table 2 have
Table 2
ID col2
1 Main 1
2 Main 2
3 Main 3
you could use a left join
select table1.Distric, table2.col2
from table1
left join table2 on table1.dictrict = t2.ID
order by table2 col2
You can use left join:
Select coalesce(t2.col, t1.District) from table1 t1
left join table2 t2 on t1.District = t2.Id

If Statements in where clause?

So I have to run a query against a database schema: http://sqlfiddle.com/#!9/d0b643 , but an example schema would look like:
Table 1
itemID sale date salesmanID storeID
---------------------------------------------------
1 1/2015 1 1
1 3/2016 1 1
2 5/2016 2 1
2 1/2015 4 1
Table 2
itemID colorID price
--------------------------------------
1 1 23
1 2 10
1 3 13
2 1 11
2 2 14
2 3 18
Table 3
ColorID color
---------------------------------------
1 Red
2 Blue
3 Green
Table 4
SaleBegin SaleEnd ColorID salesmanID storeID
----------------------------------------------------------------
1/1/2014 12/31/2014 1 0 1
1/1/2015 12/31/2015 2 0 1
1/1/2016 12/31/2016 3 0 1
1/1/2014 12/31/2014 3 2 1
1/1/2015 12/31/2016 2 2 1
I need to have something in the where clause that pretty much says if there is a SalesmanID and the saleDate from Table1 falls between the StartDate and Enddate of Table4, use that color. Otherwise, if there is no salesmanID, use the StoreID (in this example they are all 1, but they could be different).
The current query I am adding this to is:
select t1.itemID,t3.color,t2.price
from table_1 t1
LEFT JOIN table_2 t2
ON t1.itemID = t2.itemID
LEFT JOIN table_3 t3
ON t2.colorID = t3.colorID
LEFT JOIN table_4 t4
ON t3.colorID = t4.colorID
WHERE t1.sale_date BETWEEN saleBegin and saleEnd;
How can I run this? The expected results should look like:
itemID color price
1 Blue 10
1 Green 13
2 Blue 14
2 Blue 14
I am trying to use MSSQL logic. and try it in SQL fiddle it run success.
Just try this code yourself to see if this is what you want.
select t1.itemID,t3.color,t2.price from table_1 t1
LEFT JOIN table_4 t41
on t1.sale_date BETWEEN t41.saleBegin and t41.saleEnd
and t41.salesmanID!=0 and t1.salesmanID=t41.salesmanID
LEFT JOIN table_4 t42
on t1.sale_date BETWEEN t42.saleBegin and t42.saleEnd
and t42.salesmanID=0 and t1.storeID=t42.storeID
INNER JOIN table_2 t2
ON t1.itemID = t2.itemID
INNER JOIN table_3 t3
ON t2.colorID = t3.colorID and t2.colorID=IF(ISNULL(t41.colorID),t42.colorID,t41.colorID)
order by t1.itemID,t3.color,t2.price;
I think this is what you want. You will get too many rows because of overlaps between store # and Sale dates. Once I changed your sample data table4 to have the last two rows be store #2 I get the results you posted.
1/1/2014 12/31/2014 3 2 2
1/1/2015 12/31/2016 2 2 2
Select t1.itemID,t3.color,t2.price
From table_1 t1
LEFT JOIN table_4 t4 ON t1.sale_date BETWEEN t4.saleBegin And t4.saleEnd And t1.SalesmanID = t4.SalesmanID
LEFT JOIN table_4 t4a ON t1.sale_date BETWEEN t4a.saleBegin And t4a.saleEnd And t1.StoreID = t4a.StoreID
LEFT JOIN table_2 t2 ON t1.itemID = t2.itemID And t2.ColorID = t4a.ColorID
LEFT JOIN table_3 t3 ON t2.colorID = t3.colorID
Where t4.SalesmanID Is Null
Group By t1.itemID,t3.color,t2.price
Union All
Select t1.itemID,t3.color,t2.price
From table_1 t1
LEFT JOIN table_4 t4 ON t1.sale_date BETWEEN t4.saleBegin And t4.saleEnd And t1.SalesmanID = t4.SalesmanID
LEFT JOIN table_2 t2 ON t1.itemID = t2.itemID And t2.ColorID = t4.ColorID
LEFT JOIN table_3 t3 ON t2.colorID = t3.colorID
Where t4.SalesmanID Is Not Null
itemID color price
1 Blue 10.000
1 Green 13.000
2 Blue 14.000
2 Blue 14.000

Joining a table thru another property of another table that is linked with id

Edit : I did a mistake the Invoices Table carry the transactionId
I have 3 tables :
Transactions Reconciliations Invoices
id num line transId id Code transId
-- --- ---- ------- -- ---- -------------
3 1 1 3 5 Code 5 3
6 1 2 6 9 Code 9 8
7 1 3 7 12 Code 12 11
8 2 1 8
12 2 2 12
10 3 1 10
11 3 2 11
and this Query :
select
t1.id -- transaction id
t2.num -- reconciliation number
t3.Code -- Invoice code
from Transactions t1
left outer join Reconciliations t2 on t2.transId = t1.id
left outer join Invoices t3 on t3.transId = t1.id
Giving the following result :
id num code
-- --- ----
3 1 Code 5
6 1 null
7 1 null
8 2 Code 9
12 2 null
10 3 null
11 3 Code 12
But what I want is this :
id num code
-- --- ----
3 1 Code 5
6 1 Code 5
7 1 Code 5
8 2 Code 9
12 2 Code 9
10 3 Code 12
11 3 Code 12
To put words on it when the linked Invoice table gives null I want to join on all the records from Reconciliations with the same Reconciliation number.
Edit : I would like the Code in invoices to be shared across all transactions that shares the same Reconciliation number
I have tried to do thru outer apply and sub query but I cannot figure out a way to achieve it. Have you any idea ?
The solution is to join to Reconciliations again before joining to Invoices:
select t.id, r.num, i.Code
from Transactions t
join Reconciliations r on r.transId = t.id
join Reconciliations r2 on r2.num = r.num
join Invoices i on i.transId = r2.transId
Note that the joins are now inner joins (requiring a match), and how you easily make the connection to the right Invoice via the shared Reconciliation.num value - using inner joins means you only get the invoice row that matches.
To see this query in action, execute it on SQLFiddle
Edit: To cater for missing invoices
Use left join to invoices, but you need a group by with max() to limit the joins to just one invoice per transaction (without the max() you get lots of extra rows with null Code):
select t.id, r.num, max(i.Code) as Code
from Transactions t
join Reconciliations r on r.transId = t.id
join Reconciliations r2 on r2.num = r.num
left join Invoices i on i.transId = r2.transId
group by t.id, r.num
To see this query in action, where I have invalidated invoice 12 from above fiddle, execute it on SQLFiddle
You seem to want to spread the InvoiceId in Transactions up to the next value.
Here is one method:
select t.*
(select top 1 InvoiceId
from Transactions t2
where t2.id <= t.id and t2.InvoiceId is not NULL
order by id desc
) as newInvoiceId
from transactions t;
You can then substitute this into your query:
select
t1.id -- transaction id
t2.num -- reconciliation number
t3.Code -- Invoice code
from (select t.*
(select top 1 InvoiceId
from Transactions t2
where t2.id <= t.id and t2.InvoiceId is not NULL
order by id desc
) as newInvoiceId
from transactions t
) t1
left outer join Reconciliations t2 on t2.transid = t1.id
left outer join Invoices t3 on t3.id = t1.transid ;