SQL, Check if Rows are in another Table - sql

I have two tables, Stock and Warehouse.
I need to get the Items which are available in all Warehouses.
Here an example:
Stock Table:
ItemID WarehouseID ItemAmount
-------------------------------------------
1043 1 20
1043 2 2
1043 3 16
1043 4 17
1044 1 32
1044 2 12
1044 4 7
1055 2 6
 
Warehouse Table:
WarehouseID WarehouseName
-------------------------------
1 Name1
2 Name2
3 Name3
4 Name4
For the Example the result should be Item 1043 because its available in all Warehouses, unlike the other ones.
I didn't get to a solution, can anyone help me?

You could also use this "double negative" query using NOT EXISTS:
SELECT DISTINCT s.ItemID
FROM StockTable s
WHERE NOT EXISTS
(
SELECT 1 FROM Warehouse w
WHERE NOT EXISTS(SELECT 1 FROM StockTable s2
WHERE w.WarehouseID = s2.WarehouseID
AND s.ItemID = s2.ItemID)
)
Demo fiddle
This approach looks more verbose but it has some benefits:
you can change it easily if the rules are getting more complex
you can remove the DISTINCT to see all rows
you can add all columns since GROUP BY was not used
it has no issues with null values

select itemid
from stock
group by itemid
having count(distinct warehouseid) = (select count(*) from warehouse);
SQLFiddle: http://sqlfiddle.com/#!15/e4273/1
If the stock table may also contain items with an amount = 0 you need to add a where clause:
select itemid
from stock
where itemamount > 0
group by itemid
having count(distinct warehouseid) = (select count(*) from warehouse);

NOT EXISTS combined with EXCEPT:
select distinct ItemID
from stock s1
where not exists (select warehouseid from warehouse
except
select warehouseid from stock s2 where s2.ItemID = s1.ItemID);
You can even replace select distinct ItemID with select * to get all those items.

I use this query:
SELECT
ItemID
FROM
stock
GROUP BY
ItemID
HAVING
SUM(DISTINCT warehouseid) = (SELECT SUM(WarehouseID) from warehouse)
That is more reliable than using COUNT, because in a rare situation of don't making a foreign key it should returns some invalid results.

Related

How to combine some rows into a single row, and delete other rows?

I have a table like this:
id | invoice_id | product_id | quantity | total
1 5 10 2 100
2 5 10 1 50
3 5 11 1 200
4 5 11 1 200
I want to combine the rows having same product_id in an invoice by adding their quantities and total values to one of the rows and then delete the other rows in the table. So the output should be like this
id | invoice_id | product_id | quantity | total
1 5 10 3 150
3 5 11 2 400
How can I do this? I was thinking of using an sql function that returns a list of id's having the same invoice and product and then using aggregate functions on quantity and price. Are there any simpler ways to do this?
First, you need an UPDATE statement that updates for each invoice_id, product_id combination the row with the min id with the totals of quantity and total:
UPDATE tablename t
SET quantity = s.quantity,
total = s.total
FROM (
SELECT MIN(id) id, SUM(quantity) quantity, SUM(total) total
FROM tablename
GROUP BY invoice_id, product_id
) s
WHERE s.id = t.id;
Then a DELETE statement to delete all the other ids:
DELETE FROM tablename t1
WHERE t1.id > (
SELECT MIN(t2.id)
FROM tablename t2
WHERE t2.invoice_id = t1.invoice_id AND t2.product_id = t1.product_id
);
See the demo.
This looks like an aggregation query:
select min(id) as id, invoice_id, product_id,
sum(quantity) as quantity, sum(total) as total
from t
group by invoice_id, product_id;

Excluding records where criteria meets

I have a set of records where we identify several items connected to a customer.
My dilemma is that if a customer has both items then I would like to exclude that customer.
If they only have one specific item then I want to include it.
I will be using this code to create a view so i'm trying to find the best way. I could try Row_number() to identify different records, but I'm not sure that would be ideal in this situation.
Example data table:
Customer | ItemID | value1 | Value2
A 12 35 0
B 12 35 0
C 13 0 25
C 12 0 25
D 18 225 12
Desired Output:
Customer | ItemID | value1 | Value2
A 12 35 0
B 12 35 0
This is what I have so far:
select Customer, ItemID, Value1, Value2
from Table1
where itemID = 12
This would give me customer 'C', which I don't want.
If you want customers who have itemid = 12 but not itemid = 13 you can use NOT EXISTS:
select * from tablename t
where itemid = 12
and not exists (
select 1 from tablename
where customer = t.customer
and itemid = 13
)
If you want customers who have itemid = 12 and not any other itemid:
select * from tablename t
where itemid = 12
and not exists (
select 1 from tablename
where customer = t.customer
and itemid <> 12
)
or:
select * from tablename
where customer in (
select customer from tablename
group by customer
having min(itemid) = 12 and max(itemid) = 12
)
I think you need to clarify your question but, as I understand it, you're looking to return the all rows where:
1) A customer has a particular item (i.e. Item ID 12, which excludes customer D)
and
(2) They only have one item in total, which excludes customer C since they have two items.
If that is the case, then here's what I've got:
SELECT *
FROM Table1
WHERE ItemID == '12' AND
Customer in (
SELECT Customer
FROM Table1
GROUP BY Customer
HAVING Count(Customer) = 1
)
Edit: I clarified my interpretation of OP's question. I also tested my solution on SQL Fiddle (http://sqlfiddle.com/#!5/b5f1f/2/0) and updated the WHERE clause accordingly.

Need a query to find count of a column record?

I have a table like this,
ProductId CategoryID bIsPrimary
1 5 1
1 6 0
1 7 0
2 18 1
2 19 1
I need a output like this,
ProductID PrimaryCategoryCount
1 1
2 2
Basically i need to find the the number of primary categories for each product.
SELECT ProductId, COUNT(*)
FROM SomeTable
WHERE bIsPrimary <> 0
GROUP BY ProductId
SELECT
ProductId
,sum(case when bIsPrimary = 1 then 1 else 0 end) as PrimaryCategoryCount
from
Table
group by
ProductId
or
SELECT
ProductId
,count(CategoryId)
from
Table
where bIsPrimiary = 1
group by ProductId
Both will provide you the same result. Pick up one which suits you more or is faster.
SELECT ProductId, COUNT(bIsPrimary)
FROM yourTable
GROUP BY ProductId
This is how I'd do it. WHERE clause isn't necessary here if I'm not mistaken.

SQL Selecting rows with multiple values

I have these 2 tables:
Table SW_ITEM:
ID SWID ITEM_ID
1 1 99
2 2 99
3 5 99
4 2 100
5 1 100
6 1 101
7 2 102
Table ITEM:
ID FILENAME
99 abc
100 def
101 geh
102 ijk
column ITEM_ID is a foreign key to the column ID of table ITEM.
So I want all filenames which have the SWID "1" AND "2" (that would be ITEMID 99 and 100, so their filenames are "abc" and "def")
Here I have to say that it is possible that ITEM_ID has more than one entry with the same SWID, so I cannot use this SQL:
SELECT ITEM_ID FROM SW_ITEM
WHERE SWID IN (1,2)
GROUP BY ITEM_ID
HAVING COUNT(ITEM_ID) = 2
So is there any other possibility to get all entries which have the SWID 1 and 2 (creating a join for every SWID is also not an option - because with many entries it would be really slow)
Kind regards
You need to use DISTINCT in COUNT and count SWID instead of ITEM_ID:
SELECT ITEM_ID FROM SW_ITEM
WHERE SWID IN (1,2)
GROUP BY ITEM_ID
HAVING COUNT(DISTINCT SWID) = 2;
Please checkout this demo.
To retrieve all filenames, try:
SELECT ITEM_ID, FILENAME
FROM ITEM JOIN SW_ITEM ON ITEM.ID = SW_ITEM.ITEM_ID
WHERE SWID IN (1,2)
GROUP BY ITEM_ID
HAVING COUNT(DISTINCT SWID) = 2;
Demo
I have a little different problem where I have to find a person with multiple entries in the same table based on email for that the above solution didn't work for me. You can try using the following,
SELECT person_id,
(ROW_NUMBER () OVER (PARTITION BY pers_email ORDER BY pers_name) person_count
from pers_table
WHERE person_count > 2;
Try this hope it works :)

SQL query distinct - group by

I am having issues with a sql query.
I have following table (I simplified it a bit):
ChainId ComponentId TransmitEndpointId
1 156 NULL
1 156 7
1 157 7
2 510 6
2 510 6
2 511 6
2 511 8
What I need to do is get the number of TransmitEndpointId's foreach 'unique' ComponentId in a 'unique' ChainId.
So the result of the above data would be: 5 (2 unique componentId's in Chain 1 & 2 unique componentId's in Chain 2 with 2 different TransmitId's ==> NULL values don't count)
This is quite complex and have no idea on how to start with this query.
Can anybody help?
Thanks in advance.
add the where TransmitEndpointId is not null or you will get a 0 because of the NULL
SELECT ChainId,
ComponentId,
count(distinct TransmitEndpointId)
FROM chain
where TransmitEndpointId is not null
GROUP BY ChainId, ComponentId
select sum(endPointNr) from
(
SELECT count(distinct TransmitEndpointId) as endPointNr
FROM chain
where TransmitEndpointId is not null
GROUP BY ChainId, ComponentId
) X
EDIT (why add TransmitEndpointId is not null)
This will give you the unique count for each ChainID/ComponentId combination.
SELECT ChainId,
ComponentId,
count(distinct TransmitEndpointId)
FROM your_table
GROUP BY ChainId, ComponentId
Now you can use that inside a derived table to get the total count:
SELECT sum(distinct_count)
FROM (
SELECT ChainId,
ComponentId,
count(distinct TransmitEndpointId) as distinct_count
FROM your_table
GROUP BY ChainId, ComponentId
) t
I think that is what you want
Please Try this code
SELECT COUNT(DISTINCT ChainId,ComponentId,TransmitEndpointId)
FROM your_table
WHERE TransmitEndpointId IS NOT NULL