How to make joins in my criteria in SQL SERVER? - sql

I have three tables:
**1.FT_ViewItemMovement **
StoreID ItemLookupCode QTY
-------------------------------
1001 11121111 222
1001 11121111 1
1201 11121111 333
1201 11121111 2
2.Item
ItemLookupCode ID
------------------------
11121111 111
3.ItemDynamic
ItemID StoreID SnapShotQuantity
-------------------------------------
111 1201 50
111 1001 25
111 5000 75
111 7777 100
Expecting Result
ItemID StoreID QTY SnapShotQuantity
-------------------------------------
111 1201 335 50
111 1001 223 25
111 5000 0 75
111 7777 0 100
I Tried this following Query, But I didn't get
SELECT
ViewItemMovement.ItemLookupCode,
ViewItemMovement.StoreID,
Sum(ViewItemMovement.Quantity) Quantity,
ItemDynamic.SnapShotQuantity SanpShotQuantity
FROM
FT_ViewItemMovement ViewItemMovement
left join Item with(NoLock) on Item.ItemLookupCode = ViewItemMovement.ItemLookupCode
left join ItemDynamic with(NoLock) on ItemDynamic.ItemID = Item.ID and ItemDynamic.StoreID = ViewItemMovement.StoreID
WHERE brand = 'PEPSI'
Group By
ViewItemMovement.ItemLookupCode,
ViewItemMovement.StoreID,
ViewItemMovement.ItemDescription,
ViewItemMovement.Brand,
Item.Cost,
ItemDynamic.SnapShotQuantity
first I want to summarise the quanity of FT_ViewItemMovement.Qty by StoreID and ItemLookupCode and then if it matches the same itemID with ItemDynamic it has to bring SnapShotQuanity
If there is no FT_ViewItemMovement.Qty, then show FT_ViewItemMovement.Qty = 0 as Expecting output

Simplify your query by looking at what you need, which is two SUM's and a GROUP BY containing the other selections, while using StoreID from FT_ViewItemMovement to allow the SUM(v.QTY) to work.
SELECT id.ItemID, v.StoreID, SUM(v.QTY), SUM(id.SnapShotQuantity)
FROM FT_ViewItemMovement v
INNER JOIN Item i ON v.ItemLookupCode = i.ItemLookupCode
INNER JOIN ItemDynamic id ON i.ID = id.ItemID
GROUP BY id.ItemID, v.StoreID

Your GROUP BY clause looks too complicated. I think this is what you want:
SELECT vim.ItemLookupCode, vim.StoreID,
COALESCE(Sum(vim.Quantity), 0) as Quantity,
id.SnapShotQuantity as SanpShotQuantity
FROM FT_ViewItemMovement vim LEFT JOIN
Item i
ON i.ItemLookupCode = vim.ItemLookupCode LEFT JOIN
ItemDynamic id
ON id.ItemID = i.ID and id.StoreID = vim.StoreID
WHERE vim.brand = 'PEPSI'
GROUP BY vim.ItemLookupCode, vim.StoreID,
id.SnapShotQuantity;
Your WHERE clause references brand. I have no idea where that comes from based on your question.

With your data sample, you must select from ItemDynamic then use join other table.
I hope it will work for you.
SELECT
ItemDynamic.ItemID,
ItemDynamic.StoreID,
SUM(ViewItemMovement.Quantity) AS Quantity,
MAX(ItemDynamic.SnapShotQuantity) AS SanpShotQuantity
FROM
ItemDynamic with(NoLock)
left join Item with(NoLock) on Item.ID = ItemDynamic.ItemID
left join FT_ViewItemMovement ViewItemMovement on ViewItemMovement.ItemLookupCode = Item.ItemLookupCode and ViewItemMovement.StoreID = ItemDynamic.StoreID
Group By
ItemDynamic.ItemID,
ItemDynamic.StoreID

Related

Complex SQL Query in JOIN

Tables
TRANSACTIONS
SUPP_ID | PAYMENT
----------+----------
1001 200
1002 100
1005 250
MASTER_SUPPLIERS
SUPP_ID | AREA
----------+----------
1001 ABC
1002 XYZ
1003 TYU
1004 MNO
1005 PQR
Intention:
Find those count of suppliers area wise where no payment (NO_TRANS_CNT) has been received
SELECT AREA, COUNT(*) AS NO_TRANS_CNT FROM MASTER_SUPPLIERS
WHERE AREA NOT IN (SELECT DISTINCT(AREA) FROM TRANSACTIONS)
GROUP BY AREA
AREA | NO_TRANS_CNT
----------+--------------
TYU 1
MNO 1
Want to ask: Now, I also want to add the column TOTAL_SUPPLIERS in this area
AREA | TOTAL SUPPLIERS | NO_TRANS_CNT
----------+--------------------+----------------
ABC 1 0
XYZ 1 0
TYU 1 1
MNO 1 1
PQR 1 0
I think it can be achieved using JOINs, but I am not able to get how ?
Try this:
SELECT
M.AREA
, COUNT(1) TOTAL_SUPPLIERS
, COUNT(CASE WHEN T.SUPP_ID IS NULL THEN 1 END) NO_TRANS_CNT
FROM MASTER_SUPPLIERS M
LEFT JOIN TRANSACTIONS T ON T.SUPP_ID = M.SUPP_ID
GROUP BY M.AREA;
Something like
select M.AREA, COUNT(*) as TOTAL_SUPPLIERS, COUNT(T.PAYMENT) as NO_TRANS_CNT
from MASTER_SUPPLIERS M left join TRANSACTIONS T
on M.SUPP_ID = T.SUPP_ID
group by M.AREA;
could work.
Note that the COUNT(T.PAYMENT) only counts those where the PAYMENT is not NULL.
Use a left join, but start with suppliers:
select ms.area, count(*) as num_suppliers, count(t.supp_id) as num_transactions
from master_suppliers ms left join
transactions t
on t.supp_id = m.supp_id
group by ms.area;
The left join keeps everything in the first table -- which is what you want, along with matching rows from the second.
When you count the number of transactions, the argument to count() should either be a column used in the on clause or the primary key.

SQL Queue to get workload in 2 weeks [SQL Server]

Currently, the queue shows me the workload of products in a oven and for product which are in the oven too, but actually for some hours in a test outside of the oven.
I count the h with "gesamt" for each product -> this show me how Long they stay already in the oven. Mostly the products stay 1000h in the oven its defined in "Zielgröße" in the db.
What I want is that the queue should show me the workload of the oven for the next 2 weeks as a prediction (336h). Thats all "gesamt" which is over "Zielgröße" (mostly 1000) not shown in the queue maybe handled in a temporary table or whatever.
Is it possible to handle this in Micrososft SQL Server?
Here is the code:
SELECT TesterID,Name, TesterNr, COUNT(Name) as Anzahl, gesamt FROM
(SELECT AllgemeineAngaben.QualiID,
Bezeichnung,
AnzModule,
Tester.Name, TesterNr,
Testname,
v_gesamtBerechnungLaufend.TestaufstellungID,
lastRO,
gesamt,
v_gesamtBerechnungLaufend.Einheit,
v_gesamtBerechnungLaufend.PlanID,
v_gesamtBerechnungLaufend.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnungLaufend on
AllgemeineAngaben.QualiID = v_gesamtBerechnungLaufend.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnungLaufend.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnungLaufend.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
Where Tester.Name = 'KPS02'
UNION ALL
SELECT AllgemeineAngaben.QualiID,
Bezeichnung, AnzModule, Tester.Name, TesterNr,
Testname,
Testaufstellung.TestaufstellungID,
v_gesamtBerechnung.gesamt as lastRO,
v_gesamtBerechnung.gesamt,
v_gesamtBerechnung.Einheit,
v_gesamtBerechnung.PlanID,
v_gesamtBerechnung.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnung on
AllgemeineAngaben.QualiID = v_gesamtBerechnung.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnung.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnung.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
WHERE Testaufstellung.fertig ='0'
AND Testaufstellung.aktiv ='1'
AND Testaufstellung.Zielgröße > v_gesamtBerechnung.gesamt
AND Tester.Name = 'KPS02'
AND v_gesamtBerechnung.TestaufstellungID not in (Select TestaufstellungID from DB.dbo.v_gesamtBerechnungLaufend)) x
group by TesterID, Name, TesterNr, gesamt
Here the table to show in an example what I want
actual workload
TesterID Name TesterNr Anzahl gesamt
-------------- ------- ---------- ----------- -----------
Product1 8 KPS02 2 1 209
Product2 8 KPS02 2 1 216
Product3 8 KPS02 2 1 816
Product4 8 KPS02 2 1 835
workload in 2 weeks
TesterID Name TesterNr Anzahl gesamt
-------------- ------- ---------- ----------- -----------
Product1 8 KPS02 2 1 545
Product2 8 KPS02 2 1 552
the last recors are over 1000 Zielgröße, so just dont show them in the prediction queue
Product3 8 KPS02 2 1 1152
Product4 8 KPS02 2 1 1171
I hope you guys can follow me. Thanks for your help.
I'll edit this answer until it's solved, but here's my first attempt:
SELECT TesterID,Name, TesterNr, COUNT(Name) as Anzahl, gesamt + 336 as gesamt
FROM
(SELECT AllgemeineAngaben.QualiID,
Bezeichnung,
AnzModule,
Tester.Name, TesterNr,
Testname,
v_gesamtBerechnungLaufend.TestaufstellungID,
lastRO,
gesamt,
v_gesamtBerechnungLaufend.Einheit,
v_gesamtBerechnungLaufend.PlanID,
v_gesamtBerechnungLaufend.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnungLaufend on
AllgemeineAngaben.QualiID = v_gesamtBerechnungLaufend.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnungLaufend.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnungLaufend.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
Where Tester.Name = 'KPS02'
UNION ALL
SELECT AllgemeineAngaben.QualiID,
Bezeichnung, AnzModule, Tester.Name, TesterNr,
Testname,
Testaufstellung.TestaufstellungID,
v_gesamtBerechnung.gesamt as lastRO,
v_gesamtBerechnung.gesamt,
v_gesamtBerechnung.Einheit,
v_gesamtBerechnung.PlanID,
v_gesamtBerechnung.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnung on
AllgemeineAngaben.QualiID = v_gesamtBerechnung.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnung.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnung.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
WHERE Testaufstellung.fertig ='0'
AND Testaufstellung.aktiv ='1'
AND Testaufstellung.Zielgröße > v_gesamtBerechnung.gesamt
AND Tester.Name = 'KPS02'
AND v_gesamtBerechnung.TestaufstellungID not in (Select TestaufstellungID from DB.dbo.v_gesamtBerechnungLaufend)) x
group by TesterID, Name, TesterNr, gesamt
) A
WHERE gesamt + 336 < 1000
It seems to me like all you need to do is add 336 to the current values and then filter out anything less than 1000.

SQL Server select parts, fill with 0 no result

I have the following tables
Location (Id, locationName)
Inventory (productid, qty, locationid)
With the following data, I need to query to show all locations per productid, even when not in inventory table. example of records below.
Table Location
Id Location Name
--------------------
1 Plant
2 Warehouse
3 Container
Table Inventory:
Productid Qty Locationid
-----------------------------
45 30 1
45 56 2
3 15 1
3 50 3
15 25 3
Desired result for my query:
Productid Qty LocationName
---------------------------------
45 30 Plant
45 56 Warehouse
45 0 Container
3 15 Plant
3 0 Warehouse
3 50 Container
15 0 Plant
15 0 Warehouse
15 25 Container
So far I have tried many different ways but no luck, so any help will be appreciated.
You can use the following query:
SELECT p.ProductId,
COALESCE(qty,0) AS qty,
[Location Name]
FROM LOCATION l
CROSS JOIN (SELECT DISTINCT ProductId FROM Inventory) AS p
LEFT JOIN Inventory i ON l.Id = i.locationid AND p.Productid = i.Productid
ORDER BY Productid, [Location Name]
The query uses CROSS JOIN to get all possible combinations between locations and products.
Demo here
Select y., isNull(z.Quantity,0) as Quantity
From
(
Select Location., x.ProductId
From Location,(Select Distinct ProductId From Inventory) as x
) as y
Left Outer Join Inventory z ON y.Id = z.LocationId
and y.ProductId = z.ProductId

SQL find exact record combination

I have two tables, one with routes and one with order delivery data.
I need to choose for each order exact route which has all shops in it, no more no less, order of shops is not important. If I don't have exact route, I don't want to join any route to that order.
RouteId ShopId
------------------------------------
1 111
1 222
2 111
2 222
2 333
3 111
3 222
3 333
3 444
OrderId ShopId
------------------------------------
11 111
11 222
11 333
12 111
12 222
13 111
13 333
I want result set like this
OrderId ShopId RouteId
------------------------------------
11 111 2
11 222 2
11 333 2
12 111 1
12 222 1
13 111 NULL
13 333 NULL
I have around 50k-100k orders so I don't want to use cursors or any other loop if not necessary.
Any help is greatly appreciated.
Zoran
You can use FOR XML PATH in order to get into a string value all shops per OrderId and per RouteId:
;WITH RoutesCTE AS (
SELECT RouteId,
(SELECT ShopId
FROM routes AS r2
WHERE r2.RouteId = r1.RouteId
ORDER BY ShopId
FOR XML PATH('')) AS RouteShops
FROM routes AS r1
GROUP BY RouteId
), OrdersCTE AS (
SELECT OrderId, ShopId,
(SELECT ShopId
FROM orders AS o2
WHERE o2.OrderId = o1.OrderId
ORDER BY ShopId
FOR XML PATH('')) AS OrderShops
FROM orders AS o1
)
SELECT OrderId, ShopId, c2.RouteId
FROM OrdersCTE AS c1
LEFT JOIN RoutesCTE AS c2 ON c1.OrderShops = c2.RouteShops
In the above CTEs RouteShops and OrderShops hold an XML value of all shops per RouteId and OrderId respectively.
So, for example, RoutesCTE returns the following results:
RouteId RouteShops
-----------------------------------------------------------------
1 <ShopId>111</ShopId><ShopId>222</ShopId>
2 <ShopId>111</ShopId><ShopId>222</ShopId><ShopId>333</ShopId>
3 <ShopId>111</ShopId><ShopId>222</ShopId><ShopId>333</ShopId><ShopId>444</ShopId>
Comparing these two fields we can find exact matches (if any).
Demo here
Note: The above query may return more than one route per OrderId if the routes table contains RouteIds having the same combination of ShopIds. In this case you have to fiddle with the RoutesCTE (including a ROW_NUMBER in it for example).
I like the xml answer from Giorgos better but I had started on this
select t1.*
from
(
select cteS.OrderID, cteR.RouteID, count(*) as count
from cteS
join cteR
on cteS.StoreID = cteR.StoreID
group by cteS.OrderID, cteR.RouteID
) t1
join
(
select cteS.OrderID, count(*) as count
from cteS
group by cteS.OrderID
) t2
on t1.OrderID = t2.OrderID
and t2.count = t2.count
or
select OrderID, RouteID
from store
join route
on store.storeID = route.storeID
except
select OrderID, RouteID
from store
full outer join route
on store.storeID = route.storeID
where store.storeID is null or route.storeID is null
Use of LEFT JOIN put to NULL fields of secondary table (RouteTable) is there's no corrispondence in JOIN clause.
Try this:
SELECT O.*, R.RouteId
FROM OrderTable O
LEFT OUTER JOIN RouteTable R
ON O.ShopId = R.ShopId

SQL join - duplicate rows

I have three tables (simplified version - the whole picture is a bit more complex).
TABLE: CUSTOMER TABLE: PURCHASE1 TABLE: PURCHASE2
=============== ======================= =======================
CustomerID CustomerID | ProductID CustomerID | ProductID
--------------- ------------|---------- ------------|----------
1 1 | 51 1 | 81
2 1 | 52 1 | 82
3 2 | 52 1 | 83
I know the table structure isn't the best but that's not what I need help with. The products held in the purchase tables are of different types, if that helps to provide context.
I'm trying to join the tables, using a query like this:
Select
customer.customerid, purchase1.productid as P1,
purchase2.productid as P2
From
customer
Left join
purchase1 on customer.customerid = purchase1.customerid
Left join
purchase2 on customer.customerid = purchase2.customerid
Where
customer.customerid = 1;
This produces the following:
CustomerID | P1 | P2
--------------------
1 | 51 | 81
1 | 51 | 82
1 | 51 | 83
1 | 52 | 81
1 | 52 | 82
1 | 52 | 83
How do I get it to do this instead?
CustomerID | P1 | P2
-----------|------|---
1 | 51 | null
1 | 52 | null
1 | null | 81
1 | null | 82
1 | null | 83
The first table has a row for every combination of P1 and P2. The second table only has a row for each customer-product combination.
Can I do this without using UNION? The reason I ask, is that because the query will become more complex, using columns from other rows that aren't in PURCHASE1 or PURCHASE2.
If I have to use UNION, how can I do it such that I can still select from other tables and have additional columns in my query?
Use Union . See DEMO. In union, you have to have same number of columns in both queries so use NULL to match number of column in both query
Select * from (Select customer.customerid, purchase1.productid as P1, NULL as P2
from customer
INNER join purchase1
on customer.customerid = purchase1.customerid
UNION ALL
Select customer.customerid, NULL as P1, purchase2.productid as P2
from customer
INNER join purchase2
on customer.customerid = purchase2.customerid) tb
where tb.customerid = 1;
I would do it this way:
select customerid, p1, p2
from customer
left join (
select customerid, productid p1, null p2 from purchase1
union all
select customerid, null p1, productid p2 from purchase2
) using (customerid)
where customerid = 1;
SQLFiddle demo
Now you can attach rest of tables without repeated logic.
I would first of all union up all the tables and then join them to the customer table - like so:
with customer as (select 1 customerid, 'bob' name from dual union all
select 2 customerid, 'ted' name from dual union all
select 3 customerid, 'joe' name from dual),
purchase1 as (select 1 customerid, 51 productid from dual union all
select 1 customerid, 52 productid from dual union all
select 2 customerid, 52 productid from dual),
purchase2 as (select 1 customerid, 81 productid from dual union all
select 1 customerid, 82 productid from dual union all
select 1 customerid, 83 productid from dual),
-- end of mimicking your table and data; main query is below:
purchases as (select customerid, productid productid1, null productid2
from purchase1
union all
select customerid, null productid1, productid productid2
from purchase2)
select c.customerid,
c.name,
p.productid1,
p.productid2
from customer c
inner join purchases p on (c.customerid = p.customerid)
order by c.customerid,
p.productid1,
p.productid2;
CUSTOMERID NAME PRODUCTID1 PRODUCTID2
---------- ---- ---------- ----------
1 bob 51
1 bob 52
1 bob 81
1 bob 82
1 bob 83
2 ted 52
It's probably easiest to just change it to a union query like this.
select customer.customerid, purchase1.productid as P1, null as P2
from customer
left join purchase1
on customer.customerid = purchase1.customerid
union all
select customer.customerid, null as P1, purchase2.productid as P2
from customer
left join purchase2
on customer.customerid = purchase2.customerid
where customer.customerid = 1;
This uses Union, but in a slightly different way, within subqueries, which might provide you more flexibility.
select distinct t1.pID,t2.pID
from (select ID,pID from Puchase1
union all
select ID, null from Purchase1) t1
right join (select ID,pID from Purchase2
union all
select ID, null from Purchase2) t2
on t1.ID = t2.ID
where t1.ID = 1
and (t1.pID is not null or t2.pID is not null)
and (t1.pID is null or t2.pID is null)