Compare Values Between Two Tables - sql

I Have two tables, Table_A and Table_B.
I want result like the table result below, can someone help me with the SQL query?
Table_A
------------------
ID ITEM_ID QTY
------------------
1 100 2
2 101 3
3 102 5
4 103 2
------------------
Table_B
------------------
ID ITEM_ID QTY
1 100 2
2 101 4
3 102 4
4 104 2
5 105 1
------------------
RESULT
------------------
ITEM_ID QTY
100 0
101 1
102 -1
103 -2
104 2
105 1
------------------
Thanks.

You need a full join to get values from either table
select
isnull(a.item_id,b.item_id) as item_id, isnull(b.qty, 0) - isnull(a.qty, 0) as qty
from
table_a a
full outer join table_b b on a.item_id = b.item_id

select item_id, sum(qty)
from (select item_id, qty
from table_b
union all
select item_id, -qty
from table_a) x
group by item_id
order by item_id

Used full outer join and some isnulls
SQL Fiddle Example
select isnull(b.item_id, a.item_id) as ItemID,
isnull(b.qty, 0) - isnull(a.qty,0)as Qty
from table_b b
full outer join table_a a on a.item_id = b.item_id
order by itemid

Related

Join two tables on multiple columns with OR and label

I have two tables as shown here:
orderID
customerID
1
1001
2
1002
3
1003
4
1003
and the other one is like:
userID
Service1FirstOrderID
Serice2FirstOrderID
Service3FirstOrderID
1001
null
1
null
1002
2
null
null
1003
3
null
4
Now I want to join these two tables so that I can get every customer id with ServiceID that have been purchased.
UserID
Service
1001
2
1002
1
1003
1
1003
3
Any help would be appreciated.
It's possible to join on an IN
SELECT
so.userID
, CASE
WHEN o.OrderID = so.Service1FirstOrderID THEN 1
WHEN o.OrderID = so.Service2FirstOrderID THEN 2
WHEN o.OrderID = so.Service3FirstOrderID THEN 3
END AS Service
FROM Orders o
INNER JOIN ServiceOrders so
ON so.userID = o.customerID
AND o.OrderID IN (so.Service1FirstOrderID, so.Service2FirstOrderID, so.Service3FirstOrderID)
ORDER BY o.customerID;
userID
Service
1001
2
1002
1
1003
1
1003
3
Demo on db<>fiddle here
You have a heavily denormalized table structure, but it appears that this is not a join at all.
It seems to be purely a conditional unpivot of the second table, which you can do with CROSS APPLY
SELECT
t2.UserId,
v.*
FROM table2 t2
CROSS APPLY (
SELECT 1
WHERE Service1FirstOrderID IS NOT NULL
UNION ALL
SELECT 2
WHERE Service2FirstOrderID IS NOT NULL
UNION ALL
SELECT 3
WHERE Service3FirstOrderID IS NOT NULL
) v(Service);
db<>fiddle
You can achieve this using CTE.
;WITH CTE_ServiceOrder as
(
SELECT UserId, 1 AS ServiceId, Service1FirstOrderID as orderId
from ServiceOrders
where Service1FirstOrderId is not null
union all
SELECT UserId, 2, Service2FirstOrderID as orderId
from ServiceOrders
where Service2FirstOrderId is not null
union all
SELECT UserId, 3, Service3FirstOrderID as orderId
from ServiceOrders
where Service3FirstOrderId is not null
)
SELECT o.customerID, s.ServiceId FROM CTE_ServiceOrder as s
INNER JOIN Orders as o
on o.orderID = s.orderid
order by o.customerID
Thanks to #Lukstorms for create script.
You can refer to the dbfiddle

Finding orders where products of both types are present

Consider below table tbl:
ordernr productId productType
1 12 A
2 15 B
2 13 C
2 12 A
3 15 B
3 12 A
3 11 D
How can I get only rows where products of both productType's B and C are present in the order?
The desired output should be below because products of both type B and C are present in the order:
2 15 B
2 13 C
2 12 A
It might be more efficient to use use exists twice:
select t.*
from mytable t
where
exists (select 1 from mytable t1 where t1.ordernr = t.ordernr and t1.productid = 'B')
and exists (select 1 from mytable t1 where t1.ordernr = t.ordernr and t1.productid = 'C')
This query would take advantage of an index on (ordernr, productid).
One method is using a CTE to get the counts and then filter using those in the outer query:
WITH CTE AS(
SELECT ordernr,
productId,
productType
COUNT(CASE productType WHEN 'B' THEN 1 END) AS BCount,
COUNT(CASE productType WHEN 'C' THEN 1 END) AS CCount
FROM dbo.YourTable)
SELECT ordernr,
productId,
productType
FROM CTE
WHERE BCount > 0
AND CCount > 0;
You can get all the ordernrs that you need with this query:
select ordernr
from tablename
where productType in ('B', 'C')
group by ordernr
having count(distinct productType) = 2
So you can use it with the operator in:
select * from tablename
where ordernr in (
select ordernr
from tablename
where productType in ('B', 'C')
group by ordernr
having count(distinct productType) = 2
)
See the demo.
Results:
> ordernr | productId | productType
> ------: | --------: | :----------
> 2 | 15 | B
> 2 | 13 | C
> 2 | 12 | A

Query Two Different Table that have same field item

I have two table
Table_A
ID PostId Item Stock Price
1 1 A 30 10
2 1 B 40 20
3 2 A 50 5
4 3 A 50 25
Table_B
ID PostId Item_ID Sold Price
1 1 1 2 20
2 1 2 2 40
3 1 1 1 10
4 2 3 3 15
5 2 3 1 5
I want to queries from above two table that have same 'PostID' and COUNT and SUM some field group by 'PostID', expected output would be like this
Output
ID PostId Total Item Total Stock Total Buyer(s) Total Sold Total Price
1 1 2 70 3 5 70
I've try to JOIN it, but result still miss calculate
SELECT Table_A.PostId AS PostId, COUNT(Table_A.Item) AS Total_Item, SUM(Table_A.stock) AS Total_Stock, COUNT(Table_B.Item_ID) AS total_buyer, SUM( Table_B.Sold ) AS TotalSold, SUM( Table_B.Price ) AS Total_Price
FROM Table_A
LEFT JOIN Table_B
ON Table_A.PostId = Table_B.PostId
WHERE Table_A.PostId = '1'
GROUP BY Table_A.PostId
LIMIT 0 , 30
Any suggestion for this query problem?? Thank you
SELECT Table_B.PostId AS PostId,
MIN(Table_A.Total_Item) AS Total_Item,
MIN(Table_A.Total_Stock) AS Total_Stock,
COUNT(Table_B.Item_ID) AS total_buyer,
SUM( Table_B.Sold ) AS TotalSold,
SUM( Table_B.Price ) AS Total_Price
FROM Table_B
LEFT JOIN
(
SELECT PostId,
COUNT(Item) AS Total_Item,
SUM(stock) AS Total_Stock
FROM
Table_A
GROUP BY PostId
) Table_A
ON Table_B.PostId=Table_A.PostId
WHERE Table_B.PostId = '1'
GROUP BY Table_B.PostId
LIMIT 0 , 30

Need assistance with T-SQL query

I have the following table...
orderID | itemID
---------------------
100 3425
100 3432
102 4443
102 8754
102 3425
103 6511
103 1176
103 3584
107 4967
109 0067
Now I want the queries for the following...
return the number of itemIDs for each orderID, but only for those OrderIDs with 3 or more orders per orderID
Using a single query, find all the orderIDs that have itemID 3425 and list all the itemIDs for these orderIDs.
For the first one I tried...
SELECT orderid,COUNT(itemid) AS item_count
FROM orderitems
WHERE (select COUNT(orderid) from orderitems) >2
GROUP BY orderid.
But it's not giving the desired result....I am new to T-SQL please help...
Combined Query for 1 AND 2.
SELECT OrderID
FROM tableName
GROUP BY OrderID
HAVING COUNT(*) >= 3 AND
SUM(CASE WHEN ItemID = 3425 THEN 1 ELSE 0 END) >= 1
SQLFiddle Demo
UPDATE 1
If those two problems are different,
For Problem 1
SELECT OrderID
FROM tableName
GROUP BY OrderID
HAVING COUNT(*) >= 3
SQLFiddle Demo
For Problem 2
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT OrderID
FROM tableName
GROUP BY OrderID
HAVING SUM(CASE WHEN ItemID = 3425 THEN 1 ELSE 0 END) >= 1
) b ON a.OrderID = b.OrderID
SQLFiddle Demo

LEFT JOIN in 2 table

Why doesn't this query execute correctly?
SELECT pr.ProjectNumber,
SUM(ma.TotalAmount) As CostOfMaterials,
SUM(ot.TotalAmount) AS CostOfOthers
FROM [dbo].[tblProject] AS pr
LEFT JOIN [dbo].[tblCostOfMaterials] AS ma ON pr.ProjectNumber=ma.ProjectNumber
LEFT JOIN [dbo].[tblCostOfOthers] AS ot ON pr.ProjectNumber=ot.ProjectNumber
GROUP BY pr.ProjectNumber
I assume that you mean that because each table has multiple rows for a particular project number you count the same values multiple times. To avoid this you can use
;WITH ma
AS (select ProjectNumber,
SUM(TotalAmount) as CostOfMaterials
FROM [dbo].[tblCostOfMaterials]
GROUP BY ProjectNumber),
ot
AS (select ProjectNumber,
SUM(TotalAmount) as CostOfOthers
FROM [dbo].[tblCostOfOthers]
GROUP BY ProjectNumber)
SELECT pr.ProjectNumber,
CostOfMaterials,
CostOfOthers
FROM [dbo].[tblProject] AS pr
LEFT JOIN ma
ON pr.ProjectNumber = ma.ProjectNumber
LEFT JOIN ot
ON pr.ProjectNumber = ot.ProjectNumber
The reason why you get that behaviour is because you are getting mini Cartesian joins
WITH tblProject (ProjectNumber) AS
(
SELECT 1
),tblCostOfMaterials(ProjectNumber, TotalAmount) AS
(
SELECT 1,101 UNION ALL
SELECT 1,201 UNION ALL
SELECT 1,301
),
tblCostOfOthers(ProjectNumber, TotalAmount) AS
(
SELECT 1,100 UNION ALL
SELECT 1,200
)
SELECT *
FROM [tblProject] AS pr
LEFT JOIN [tblCostOfMaterials] AS ma ON pr.ProjectNumber=ma.ProjectNumber
LEFT JOIN [tblCostOfOthers] AS ot ON pr.ProjectNumber=ot.ProjectNumber
Returns
ProjectNumber ProjectNumber TotalAmount ProjectNumber TotalAmount
------------- ------------- ----------- ------------- -----------
1 1 101 1 100
1 1 101 1 200
1 1 201 1 100
1 1 201 1 200
1 1 301 1 100
1 1 301 1 200
You can see that the values are duplicated by the number of matching rows in the other table so the SUM will be incorrect.