SQL how to SELECT an id based on multiple rows conditions - sql

I am working with nodejs and postgresql. My postgresql relation has 3 columns:
id
lesson_id
tag_id.
A lesson could belong to 1 or multiple tags.
I am trying to select all the lesson whose belongs to the requested tags.
For example
tags requested are id 10 and 2, the query should response with lesson id = 3
tags requested are id 1 and 17, the query should response with lesson id = 6
tag requested is 3, the query should response with lessons id 1, 2, 4
I have tried some sql queries like this one:
const selectLessonByTag = await pgClient.query(
`SELECT DISTINCT ON (lesson_id)
lesson_id FROM "lesson_has_tag"
WHERE tag_id = $1 AND tag_id = $2
GROUP BY lesson_id
ORDER BY lesson_id`,
[2,10]);
but it's not the expected answer.

You can use not exists like so:
select distinct lesson_id
from lesson_tags as lt1
where not exists (
select *
from (values (10), (2)) as required_tags(tag_id)
where not exists (
select *
from lesson_tags as lt2
where lt2.lesson_id = lt1.lesson_id and lt2.tag_id = required_tags.tag_id
)
)
It is difficult to digest so little explanation:
There is a table valued constructor called required_tags containing values 10 and 2
The inner query tests if 10 or 2 do not exist for a lesson from the outer query
If the inner query does not produce a match the outer row selected
DB<>Fiddle

Related

SQL for Exclude

I have a table which is a simple lists of ID numbers and NAMES - I am trying to write a SQL which only returns rows where the NAME does not have particular IDs.
This has been stumping me - the query below returns all as they have other IDs from the exclude lists (large range of IDs). How to structure a query where only those who don't have ID 2 or 3 are returned -- i.e. only returns 'bob' for table below.
select * from TABLE where ID not in (2, 3)
ID NAMES
1 bob
1 alice
2 alice
1 dave
2 dave
3 dave
4 dave
Thank you.
One method is group by and having:
select name
from t
group by name
having sum(case when ID in (2, 3) then 1 else 0 end) = 0;
If you want the original ids, you can add listagg(id, ',') within group (order by id) to the select. Or use not exists:
select t.*
from t
where not exists (select 1
from t t2
where t2.name = t.name and
t2.id in (2, 3)
);

Reuse of select query result oracle

I've got following query
SELECT ID FROM MARMELADES mrm
where not exists
(SELECT 1 FROM TOYS toys
WHERE mrm.ID = toys.ID
AND mrm.INGREDIENT = toys.INGREDIENT
AND mrm.BOX_TYPE = 2)
AND mrm.BOX_TYPE = 2
It returns almost 400+ results of id, for example [12, 33, 45, ... , 3405]
Now, i want to remove all ids that are from that list everywhere from my database. this is not only MARMELADES and TOYS. Also, i have for example 35+ tables where i can have this id).
I would be happy if this query could extract in some functions like ALL_UNNEEDED_IDS so i can use it like this:
DELETE FROM ANOTHER_TABLE_1 WHERE ID IN ( ALL_UNNEEDED_IDS )
DELETE FROM ANOTHER_TABLE_2 WHERE ID IN ( ALL_UNNEEDED_IDS )
DELETE FROM ANOTHER_TABLE_3 WHERE ID IN ( ALL_UNNEEDED_IDS )
DELETE FROM ANOTHER_TABLE_4 WHERE ID IN ( ALL_UNNEEDED_IDS )
...
DELETE FROM ANOTHER_TABLE_35 WHERE ID IN ( ALL_UNNEEDED_IDS )
It is possible to do it in oracle to reuse such results?
Use the first query within your subsequent queries. IE:
DELETE FROM ANOTHER_TABLE_1 WHERE ID IN (
SELECT ID FROM MARMELADES mrm
where not exists
(SELECT 1 FROM TOYS toys
WHERE mrm.ID = toys.ID
AND mrm.INGREDIENT = toys.INGREDIENT
AND mrm.BOX_TYPE = 2)
AND mrm.BOX_TYPE = 2
);
When you get to the toys and marmelades tables, you'll need a temporary holder table as #Gordon suggests.

Sqlite query - How I can select a predecessor?

I have this table below:
ID name Last
0 Joe Doe
1 Hut Nob
2 Lis Hug
3 Edy mur
I use this query to select an ID:
SELECT name FROM myDatabase WHERE ID = 2
In this case the query returns me the string Lis, now, How I can select the predecessor value?
Simple, the predecessor from 2 is 1, so I need only to do WHERE ID < 2 or WHERE ID = 2 - 1.
But this method have a problem! Lets suppose that I delete that row (ID = 1), the query will return null, because that ID not exists.
So, in this example, how I can select the predecessor from ID 2 and return ID 0? (ID 1 is gone)
You can use subquery to find max ID that is lower than ID that you provided:
SELECT *
FROM mytable m
WHERE m.id = (SELECT MAX(m2.id)
FROM mytable m2
WHERE m2.ID < 2);
SqlFiddleDemo
Get all the smaller IDs, and from those, take only the largest one:
SELECT name
FROM MyTable
WHERE ID < 2
ORDER BY ID DESC
LIMIT 1;

Find parent based on child table keywords

I'm trying to get the parents based on matching keywords using a child table:
AssetKeyword
============
AssetID (int)
KeywordID (int)
I'm trying to find the Assets having entries in the table, for example keywords 3 and 4 and 5.
I've tried subqueries and aggregates but can't get my head around it. Thankful for any help. Those fridays...
This isn't very dynamic i guess..
select
AssetID
from (
select distinct
AssetID,
KeywordID
from AssetKeyword
where
KeywordID in (3,4,5)
) t
group by
AssetID
having
COUNT(*) = 3
You can use EXISTS:
SELECT a.AssetID, a.Col2, ...
FROM dbo.Asset a
WHERE EXISTS
(
SELECT 1 FROM AssetKeyword ak -- it doesn't matter what you "select" here
WHERE ak.AssetID = a.AssetID
AND ak.KeywordID IN (3, 4, 5)
)
This selects all parent records where there is at least one child with at least one of those keywords.

How to GROUP multiple records from two different SQL statements

I have a table called tbl which contains all the data I need. I have many columns in this table, but for purposes of this example I will only list the columns necessary to accomplish this task.
Here's how data stored in the tbl (note uID is char(20) and cID is int)*:
uID cID
1 10
1 11
1 12
2 11
We usually query this table like
SELECT * FROM tbl WHERE uID = "1"
So it returns
uID cID
1 10
1 11
1 12
But I also need to return the row where uID is different but cID do match. Or grab the uID of the second row (which is 2) based on cID and do a select statement like this:
SELECT * FROM tbl WHERE uID in ('1','2')
That query will return what I'm looking for
uID cID
1 10
1 11
1 12
2 11
This table contains a lot of rows and I want to be able to do this programatically for every call where cID matches and uID is different.
Any suggestions?
I think this may be what you want:
SELECT *
FROM tbl
WHERE uID = '1'
UNION ALL
SELECT *
FROM tbl
WHERE uID <> '1' AND
EXISTS (select 1 from tbl tbl2 where tbl2.uId = '1' and tbl2.cID = tbl.cID);
or something like this:
SELECT uID, cID
FROM tbl
WHERE uID IN
(
SELECT uID
FROM tbl
INNER JOIN
(
SELECT cID
FROM tbl
GROUP BY cID
HAVING count(*) > 1
) c ON c.cID = tbl.cID
)