SQL Selecting rows with multiple values - sql

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 :)

Related

One query that matches values with only one condition out of two, one query that matches values with both conditions

I'm having some sort of a blank about how to do this in SQL.
Consider this reprex in R
set.seed(123)
data.frame(ID = (sample(c(1:5), 10, replace = T)),
status = (sample(c("yes", "no"), 10, replace = T)),
amount = (sample(seq(1,50,0.01),10)))
which gives out this table
ID status amount
1 3 no 29.87
2 3 yes 26.66
3 2 yes 15.49
4 2 yes 18.89
5 3 yes 44.06
6 5 no 30.79
7 4 yes 17.13
8 1 yes 6.54
9 2 yes 45.68
10 3 yes 12.66
I need to find two SQL queries.
One where I select the ID's that only have status of 'NO'
meaning ID 5.
and
One where I select the ID's that match both conditions, meaning ID 3
I have a query for both but I'm almost sure it's not correct so any lead is more than welcome.
Thanks
One where I select the ID's that only have status of 'NO' meaning ID 5.
select id from your_table where status='no' and id not in (select id from
your_table where status='yes')
One where I select the ID's that match both conditions, meaning ID 3
select id from your_table where status='no' and id in (select id from
your_table where status='yes')
At last I think you are expecting ids which do not match these conditions. so UNION both queries and get ids of your table which not exists after UNION
select id from your_table where id not in (
select id from your_table where status='no' and id not in
(select id from your_table where status='yes')
union all
select id from your_table where status='no' and id in
(select id from your_table where status='yes')
)

Return Records that span over two tables in a 1 to many relationship with multiple criteria on the many side

I am trying to get a count of records of data that spans over three tables. I have a table of products, a table of groups and a table showing which groups a product is in. As below:
Product
Product_ID
Product_Name
1
A Product
2
Another Product
Group
Group_ID
Group_Name
10
Group A
20
Group B
30
Group C
40
Group D
Product Grouping
Product_ID
Group_ID
1
10
1
20
1
30
2
20
2
40
3
50
I am trying to write a query that will, given the condition of group ids of say for example (10,20,30), it will return product 1. And if I give group ids of say (20), it will return product 1 and product 2
I have tried:
select * from product_grouping
where group_id = 10 and group_id = 20 and group_id = 30
Use aggregation and having:
select pg.group_id
from product_grouping pg
where pg.group_id in (10, 20 30)
group by product_id
having count(*) = 3;
If the product groupings can be duplicated, use having count(distinct pg.group_id) = 3.

How to count over rows and avoid duplicates?

For a university project I have to calculate a kpi based on the data of one table. The table stores data about baskets of a supermarket and the shopped line items and their product category. I have to calculate a number of all product categories of products which were bought in a specific store. So in tables it looks like this:
StoreId BasketID CategoryId
1 1 1
1 1 2
1 1 3
1 2 1
1 2 3
1 2 4
2 3 1
2 3 2
2 3 3
2 4 1
As a result of the query I want a table which counts the distinct product categories over all basket associated to a store.
Something like this:
StoreId Count(CategoryId)
1 4
2 3
If I do a not dynamic statement with hard values, it is working.
select basket_hash, store_id, count(DISTINCT retailer_category_id)
from promo.checkout_item
where store_id = 2
and basket_hash = 123
GROUP BY basket_hash, store_id;
But when I try to write it in a dynamic way, the sql calculates the amount per basket and adds the single amounts together.
select store_id, Count(DISTINCT retailer_category_id)
from promo.checkout_item
group by store_id;
But like this it isn't comparing the categories over all baskets associated to a store and I'm getting duplicates because a category can be in basket 1 and in basket 2.
Can somebody pls help?!
Thx!
As your expected result, Do you want following statement?
SELECT StoreId, COUNT(*)
FROM (
SELECT DISTINCT StoreId, CategoryId
FROM table_name
)
GROUP BY StoreId;
Please, replace "table_name" in statement by your table's name.
I'm not sure what is "dynamic way" meaning.
I'm confused by your requirements. This is what I suppose you mean:
with checkout_item (store_id, basket_hash, retailer_category_id) as (
values
(1,1,1),(1,1,2),(1,1,3),(1,2,1),(1,2,3),
(1,2,4),(2,3,1),(2,3,2),(2,3,3),(2,4,1)
)
select distinct store_id, basket_hash, store_cats, basket_cats
from (
select store_id, basket_hash,
max(store_cats) over (partition by store_id) as store_cats,
max(basket_cats) over (partition by basket_hash) as basket_cats
from (
select store_id, basket_hash,
dense_rank() over (
partition by store_id
order by retailer_category_id
) as store_cats,
dense_rank() over (
partition by basket_hash
order by retailer_category_id
) as basket_cats
from checkout_item
) s
) s
order by 1, 2
;
store_id | basket_hash | store_cats | basket_cats
----------+-------------+------------+-------------
1 | 1 | 4 | 3
1 | 2 | 4 | 3
2 | 3 | 3 | 3
2 | 4 | 3 | 1

SQL, Check if Rows are in another Table

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.

SQL - Order by amount of occurrences

It's my first question here so I hope I can explain it well enough,
I want to order my data by amount of occurrences in the table.
My table is like this:
id Daynr
1 2
1 4
2 4
2 5
2 6
3 1
4 2
4 5
And I want it to sort it like this:
id Daynr
3 1
1 2
1 4
4 2
4 5
2 4
2 5
2 6
Player #3 has one day in the table, and Player #1 has 2.
My table is named "dayid"
Both id and Daynr are foreign keys, together making it a primary key
I hope this explains my problem enough, Please ask for more information it's my first time here.
Thanks in advance
You can do this by counting the number of times that things occur for each id. Most databases support window functions, so you can do this as:
select id, daynr
from (select t.*, count(*) over (partition by id) as cnt
from table t
) t
order by cnt, id;
You can also express this as a join:
select t.id, t.daynr
from table as t inner join
(select id, count(*) as cnt
from table
group by id
) as tg
on t.id = tg.id
order by tg.cnt, id;
Note that both of these include the id in the order by. That way, if two ids have the same count, all rows for the id will appear together.