Get all elements which have both values grouped by ParentId - postgresql

I have the following problem:
I have a relation table like this:
ParentId | ValueId
1 1
1 2
2 3
2 4
2 1
Then, I want to get the ParentId who have exactly the values which query say, no more, no less.
I have this query actually:
SELECT "ParentId" FROM public."ParentValueRelation"
WHERE "ValueId" = 1 AND "ValueId" = 2
GROUP BY "ParentId"
Expected to receive 1 but getting null
Answer in sequelize could be great but not necessary

There are number of ways to do this in Postgres. Like this for instance:
SELECT "ParentId" FROM public."ParentValueRelation"
WHERE "ValueId" = 1 OR "ValueId" = 2
GROUP BY "ParentId"
HAVING COUNT("ValueID")=2
If there are duplicates in the table, you need to replace the having clause with
HAVING COUNT(DISTINCT "ValueID")=2
Best regards,Bjarni

Related

Finding and creating missing rows in table

Hello postgres experts,
I have an app where users can vote on a poll. My schema looks like this:
polls table:
id
name
1
Favorite fruit
options table:
id
poll_id
content
1
1
apple
2
1
orange
3
1
grape
4
1
banana
participants table:
id
poll_id
name
1
1
John
2
1
Jane
votes table:
id
poll_id
participant_id
option_id
type
1
1
1
1
yes
2
1
1
3
yes
3
1
2
2
yes
I made the poor choice of deciding to not create rows for "no" votes in the votes table thinking it would "save space". I realize now that it was not such a great idea because in the future I would like to know whether the user explicitly voted "no" or if perhaps the option was added after they voted and thus did not have the option to choose it. So I need to run a query that will fill all the missing "no" votes in the votes table for existing participants. The final result should look like this:
votes table:
id
poll_id
participant_id
option_id
type
1
1
1
1
yes
2
1
1
3
yes
3
1
2
2
yes
4
1
1
2
no
5
1
1
4
no
6
1
2
1
no
7
1
2
3
no
8
1
2
4
no
I have a dbfiddle with all the data already in it:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=7d0f4c83095638cc6006b1d7876d0e01
Side question: Should I be concerned about the size of the votes table in this schema? I expect it to quickly blow up to millions of rows. Is a schema where options are stored as an array in the polls table and votes stored in the participants table a better idea?
Thank you for your help.
You seem to be looking for a JOIN of participants with options, EXCEPT the rows that already are in votes. There are various ways to do that, but most straightforward:
INSERT INTO votes(poll_id, participant_id, option_id, type)
SELECT poll_id, participant_id, option_id, 'no'
FROM (
SELECT o.poll_id, p.id, o.id
FROM options o
JOIN participants p ON o.poll_id = p.poll_id
EXCEPT
SELECT poll_id, participant_id, option_id
FROM votes
) AS missing;
Alternatively:
INSERT INTO votes(poll_id, participant_id, option_id, type)
SELECT o.poll_id, p.id, o.id, 'no'
FROM options o
JOIN participants p ON o.poll_id = p.poll_id
WHERE NOT EXISTS (
SELECT *
FROM votes
WHERE poll_id = o.poll_id AND participant_id = p.id AND option_id = o.id
);
Or, assuming you already have UNIQUE index on votes, just
INSERT INTO votes(poll_id, participant_id, option_id, type)
SELECT o.poll_id, p.id, o.id, 'no'
FROM options o
ON CONFLICT ON CONSTRAINT votes_p_key
DO NOTHING;

Delete matching with already matched user in all ways in PostgreSQL

I need to delete matching of my user which are already match. So I have a table : "MatchingUser" that look like this :
id | idUser1 | idUser2
1 1 2
2 1 3
3 1 2
4 2 1
In this example I would like to delete entry 3 and 4 because the matching is the same as the entry 1 like : if 1 match with 2 I need to delete 3 because it's the same matching and also 4 because 2 matching 1 is the same as 1 matching 2.
I already have this :
DELETE FROM "WU_MatchingUsers" WHERE "id" IN (SELECT "id" FROM (SELECT "id", ROW_NUMBER() OVER( PARTITION BY "IDWU_User1", "IDWU_User2" ORDER BY "id" DESC) AS row_num FROM "WU_MatchingUsers") t WHERE t.row_num >1);
This one already delete same matching so in our example this one already delete the entry 3 but not the 4, I would like to add something to this query to also delete the entry 4.
I would use an EXISTS condition
delete from MatchingUser mu1
where exists (select *
from MatchingUser mu2
where mu2.id < mu1.id
and least(mu2.iduser1, mu2.iduser2) = least(mu1.iduser1, mu1.iduser2)
and greatest(mu2.iduser1, mu2.iduser2) = greatest(mu1.iduser1, mu1.iduser2))
This deletes all rows where the combination of iduser1/iduser2 is the same but have a higher ID value than the existing ones. So in this case rows with ID = 3 and ID = 4.

How can I join table to delete duplicates entry in PostgreSQL

I actually have this which is working :
DELETE FROM "WU_MatchingUsers" WHERE "id" IN (SELECT "id" FROM (SELECT "id", ROW_NUMBER() OVER( PARTITION BY "IDWU_User1", "IDWU_User2" ORDER BY "id" ASC) AS row_num FROM "WU_MatchingUsers") t WHERE t.row_num >1);
This delete all duplicates entry by the more recent one in "WU_MatchingUsers" but now I have another table which is : "WU_UsersSpheres" which contain Sphere id associate with user ID.
Now I would like that my query can filter / delete only Users from a specific Spheres.
So Wu_UserSpheres look like this :
id | idSpheres | IDUser
1 1 1
2 1 2
3 2 3
4 2 4
5 2 5
So the goal is to only delete duplicate of my matching where id of the users are in a specific Spheres.

TSQL Update value to 1 if Max value between two table else 0

I have two table
TABLE 1 : Stage_product
PRODUCT_ID SYS_ROWDATETIMEUTC
1 2015-03-13 06:09:30.040
2 ....
3
TABLE 2 : DIM_Product
PRODUCT_ID SYS_ROWSTARTDATETIMEUTC SYS_ROWISCURRENT
1 2014-03-13 06:09:30.040 0
2 2015-03-13 06:09:30.040 1
I want to do an update statement that if the value SYS_ROWDATETIMEUTC in the first table is more recent than the value SYS_ROWSTARTDATETIMEUTC in the table, then the value SYS_ROWISCURRENT in the second table is set to 0, else 1.
You can use the following query:
UPDATE t2
SET t2.SYS_ROWISCURRENT = CASE
WHEN t1.SYS_ROWDATETIMEUTC > t2.SYS_ROWSTARTDATETIMEUTC THEN 0
ELSE 1
END
FROM Table2 t2
INNER JOIN Table1 t1 ON t2.PRODUCT_ID = t1.PRODUCT_ID
I assume you want to compare dates between the two tables for the same product.

How to determine whether a value exists in a junction table and return zero or one?

I am using SQL Server 2008 R2
I am trying to write a single query that will return only exactly what I need. I will drop in a MovieID and get back a list of ALL genres. If the movie represents a specific genre (has an associated record in the junction table), the Checked value will be 1. If not, then 0.
My result set should look like this:
GenreID Genre Checked
1 ABC 0
2 DEF 1
3 HIJ 0
4 KLM 1
My First table is named Genres. It looks like this:
GenreID Genre
1 ABC
2 DEF
3 HIJ
4 KLM
My second table is named Movies. It looks like this:
MovieID Title
1 Blah
2 Foo
3 Carpe
4 Diem
My third table is a junction table named Movies_Genres. It looks like this:
MovieID GenreID
1 2
1 1
1 4
2 1
2 3
3 4
4 1
I would normally, do a couple of queries and a couple of loops to handle this, but I want to really just make the database do the work here. How do I tweak my query so that I can get the resultset that I need with just a single query?
Here's the starting query:
SELECT GenreID,
Genre
FROM Genres
Thanks in advance for your help!!!
SELECT g.GenreID, g.Genre, Checked = CASE WHEN EXISTS
(SELECT 1 FROM dbo.Movies_Genres AS mg
INNER JOIN dbo.Movies AS m
ON mg.MovieID = m.MovieID
WHERE mg.GenreID = g.GenreID
AND m.MovieID = #MovieID) THEN 1 ELSE 0 END
FROM dbo.Genres AS g
ORDER BY g.GenreID;
If there is a unique constraint or primary key on dbo.Movies_Genres(MovieID, GenreID) then this can be simply:
SELECT g.GenreID, g.Genre, Checked = COUNT(mg.GenreID)
FROM dbo.Genres AS g
LEFT OUTER JOIN dbo.Movies_Genres AS mg
ON g.GenreID = mg.GenreID
AND mg.MovieID = #MovieID
GROUP BY g.GenreID, g.Genre;
...since the count for any genre can only be 0 or 1 given a single #MovieID.
Pretty straight forward using CASE;
SELECT DISTINCT g.GenreID, g.Genre,
CASE WHEN mg.MovieID IS NULL THEN 0 ELSE 1 END Checked
FROM Genres g
LEFT JOIN Movies_Genres mg
ON g.GenreID=mg.GenreID
AND mg.MovieId=#MovieID;
Demo here.
Edit: If entries are guaranteed to be unique in Movies_Genres, you could choose to drop the DISTINCT.
The #MovieID is the movie, you want to filter by.
SELECT Genres.GenreID,
Genres.Genre,
CASE WHEN (Movies_Genres.GenreID IS NULL)
THEN 0
ELSE 1
END AS Checked
FROM Genres LEFT JOIN
Movies_Genres ON Movies_Genres.GenreID = Genres.GenreID AND
MovieID = #MovieID