Difficult SQL Request? - sql

I have this table tagMusic
id tagid musicid
---------------------
1 1 141
2 4 141
3 3 102
So I need to say:
take me all the music ID who have tag Id 1 AND 4 (for example ).

One way about it is to select only those tags and count how many unique results you got per tag:
SELECT musicid
FROM tagmusic
WHERE tagid IN (1, 4)
GROUP BY musicid
HAVING COUNT(*) = 2

Related

How to write SQL subqueries with count?

I'm using mysql. I want to count the minimum, maximum, and average number of different tags per movie from one table.
Exclude the duplicate:
same tag given by the same user to the same movie
same tag given by different users to the same movie
Example: table 'tags'
userId
movieId
tag
1
1
crime
1
2
dark
1
2
dark
2
2
greed
2
2
dark
3
3
music
3
3
dance
3
3
quirky
4
3
dance
4
3
quirky
Expect result:
movieId
Min_Tag
Max_Tag
Avg_Tag
1
1
1
1
2
1
2
0.66...
3
1
2
0.6
I try to write query like below, but it shows an error.
SELECT
DISTINCT movieId,
MIN(COUNT(DISTINCT tag) AS Min_Tag,
MAX(COUNT(DISTINCT tag) AS Max_Tag,
AVG(COUNT(DISTINCT tag) AS Avg_Tag,
FROM (
SELECT userId,movieId,tag
FROM tags
GROUP BY userId, movieId, tag
) AS non_dup
GROUP BY movieId;
You have to rewrite your query
First you need the count per tag and movie
and fromm that you can calculate min max and avg
SELECT
movieId,
MIN(count_tag) AS Min_Tag,
MAX(count_tag) AS Max_Tag,
AVG(count_tag) AS Avg_Tag
FROM
(SELECT movieId,tag, count(*) count_tag
FROM tags
GROUP BY movieId, tag) non_dup
GROUP BY movieId
movieId
Min_Tag
Max_Tag
Avg_Tag
1
1
1
1.0000
2
1
3
2.0000
3
1
2
1.6667
fiddle

How to avoid using a subquery for exclusion in a many-to-many sql model?

Let's say we have a model with posts and tags with a many to many relationship.
For example :
Posts table
Id
Title
HtmlContent
1
Cat eating a cucumber
...
2
Chicken flying above a cucumber
...
3
Cucumber taking revenge
...
Tags table
Id
Label
1
cat
2
chicken
3
vegetables
4
funny
PostsTags association table
Id
PostId
TagId
1
1
1
1
1
3
1
1
4
2
2
2
2
2
3
2
2
4
3
3
1
3
3
3
Yesterday my objective was to find the number of Posts not involving a cat nor being funny (i.e. I don't want Posts having a connection with Tags 1 or 4).
The query I came up with was this one :
select count(p.Id)
from posts p
where p.Id not in (
select postid
from poststags
where TagId in (1, 4)
group by postid
)
I am wondering if there is a way to exclude posts in the many-to-many relationship without executing any subquery ?
FYI I am using an SQLite database.
You can use aggregation and window function COUNT():
SELECT DISTINCT COUNT(CASE WHEN SUM(tagid IN (1, 4)) = 0 THEN 1 END) OVER ()
FROM PostsTags
GROUP BY postid
Or, window function SUM():
SELECT DISTINCT SUM(SUM(tagid IN (1, 4)) = 0) OVER ()
FROM PostsTags
GROUP BY postid
See the demo.

How to select id when same id has multiple rows but I am looking for id which are missing a particular value

I have this table my_table_c with the below values
SELECT * FROM my_table_c
ID GROUP_ID GROUP_VALUE
1 2 1
3 3 2
3 4 1
5 4 1
5 2 1
2 2 2
2 3 2
2 4 1
I am looking for this output where I get only the ID which do not have group_id 2. Additionally, I don't want to get the ID where group_id 2 is absent but other group ids are present.
If group_id 2 is absent, that's my target id.
So with the values shown in table above, I just expect ID = 3 to be returned as other ids 1, 5 and 2 each have rows where group_id = 2.
Can anyone please help with a query to fetch this result.
You could get all the id's that have group_id = 2 and use NOT IN
select *
from my_table_c
where id not in (select id from my_table_c where group_id = 2)
Another way but using NOT EXISTS
select *
from my_table_c mtcA
where not exists (select *
from my_table_c mtcB
where mtcA.id = mtcB.id and mtcB.group_ID = 2)

PSQL get duplicate row

I have table like this-
id object_id product_id
1 1 1
2 1 1
4 2 2
6 3 2
7 3 2
8 1 2
9 1 1
I want to delete all rows except these-
1 1 1
4 2 2
6 3 2
9 1 2
Basically there are duplicates and I want to remove them but keep one copy intact.
what would be the most efficient way for this?
If this is a one-off then you can simply identify the records you want to keep like so:
SELECT MIN(id) AS id
FROM yourtable
GROUP BY object_id, product_id;
You want to check that this works before you do the next thing and actually throw records out. To actually delete those duplicate records you do:
DELETE FROM yourtable WHERE id NOT IN (
SELECT MIN(id) AS id
FROM yourtable
GROUP BY object_id, product_id
);
The MIN(id) obviously always returns the record with the lowest id for a set of (object_id, product_id). Change as desired.

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