Condition filtering SQL - sql

I have a table
Table name - commands
id
name
status
group_id
id - number
name - string
status - 0 or 1
group_id - number
I need to sort as follows: for all elements with the same group_id I have to check if at least one has a status of 1, if so, then leave, if not, then remove such a group and so on for all group_id
I tried to do it through GROUP BY, and then using HAVING to remove unnecessary groups, but this way I don't get the whole table to be displayed or a query that does not work.
I think it should look like:
SELECT COUNT(*) FROM commands GROUP BY group_id HAVING *condition*
Please let me know if there are any other commands to use.
id
name
status
group_id
1
name1
0
1
2
name2
0
1
3
name3
0
2
4
name4
1
2
5
name5
1
2
6
name6
0
3
7
name7
1
4
Result:
id
name
status
group_id
3
name3
0
2
4
name4
1
2
5
name5
1
2
7
name7
1
4

In Postgres, that's a good spot to use a boolean window function:
select *
from (
select t.*, bool_or(status = 1) over(partition by group_id) has_status_1
from mytable t
) t
where has_status_1
bool_or checks if any row in the group satisfies its predicate ; we can use this information for filtering.
The upside is that the table is scanned only once, as opposed to the correlated subquery solution.

You may use EXISTS operator with a correlated subquery as the following:
SELECT id, name, status, group_id
FROM table_name T
WHERE EXISTS(SELECT 1 FROM table_name D WHERE D.group_id = T.group_id AND D.status=1)
ORDER BY id
See a demo.

Related

How to get ROW_NUMBER to start over (reset) after ROW_NUMBER reaches a certain number

I need my ROW_NUMBER column to start over if it counts up to three per taskName. There can be multiple amounts of tasks with the same name so if there are over three tasks with the same name I need the ROW_NUMBER column to start over.
My code below only gets my ROW_NUMBER column to reset after a new task name is present, however, I need it to do that and reset the ROW_NUMBER column back to one if the number gets up to three and another task with the same name still exists.
SELECT t.[taskId], tq.name as taskName,
ROW_NUMBER() OVER(PARTITION BY tq.name
ORDER BY tq.name) AS RowNum
FROM Task t (NOLOCK)
order by tq.name asc
Current Results:
taskID taskName RowNum
1 Name1 1
2 Name1 2
3 Name1 3
4 Name1 4
5 Name1 5
6 Name1 6
8 Name2 1
8 Name2 2
Expected Results:
taskID taskName RowNum
1 Name1 1
2 Name1 2
3 Name1 3
4 Name1 1
5 Name1 2
6 Name1 3
8 Name2 1
8 Name2 2
Use modulo arithmetic:
SELECT t.[taskId], tq.name as taskName,
1 + (ROW_NUMBER() OVER (PARTITION BY tq.name ORDER BY tq.name) - 1) % 3 AS RowNum_3
FROM Task t
ORDER BY tq.name asc;
Assuming the database is MSSQL:
SELECT t.[taskId], tq.name as taskName,
CASE
WHEN (ROW_NUMBER() OVER(PARTITION BY tq.name ORDER BY tq.name))%3 = 0 THEN 3
ELSE (ROW_NUMBER() OVER(PARTITION BY tq.name ORDER BY tq.name))%3
END AS RowNum
FROM Task t (NOLOCK)

How to union query results but exclude matches based on two columns being equal

I'm trying to combine results from 2 queries but eliminate rows based on whether two columns are equal.
Here's a quick example:
select * from func1(arg1) q1
name id parent
----------------------
name1 0 10
name2 1 12
select * from func1(arg2) q2
name id parent
----------------------
name4 10 42
name5 11 42
name6 12 42
What I can currently get working is:
select * from
(select * from func1(arg1))
union
(select * from func1(arg2))
but this combination will return 5 total rows (a regular union of q1 and q2).
name id parent
----------------------
name1 0 10
name2 1 12
name4 10 42
name5 11 42
name6 12 42
I'm looking for 3 total rows like this:
name id parent
----------------------
name1 0 10
name2 1 12
name5 11 42
ie, if a row in q2 has an id that exists as a parent in q1, then exclude it in the union's result.
Essentially, this combines "children" and "childless parents"
Additional question: Is it possible to order the results to go by q1.parent unless rows exist in q2 after elimination, in which case we'd "insert" the q2 rows into the result set of q1 based on q1.parent and q2.id?
Example result ordering:
name id parent
----------------------
name1 0 10
name5 11 42
name2 1 12
something like this should work:
select * from
(select * from func1(arg1) a where not exists (select 1 from func1(arg2) b where a.id = b.parent))
union
(select * from func1(arg2))
Can't you just add a where clause onto the second select?
(select * from func1(arg2)
where ID not in (select parent from func1(arg1))
Or maybe you need to select the union into a temp table and then apply the filter to a new select from the results.
I don't have access to a DB right now to fiddle around with it.

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 show distinct column

I have a table like this and need to add column which will show info only in distinct rows:
ID Name
1 1001
2 1001
3 1001
4 1001
5 1002
6 1002
7 1002
8 1003
9 1004
10 1004
I need such result:
ID Name Result
1 1001 1
2 1001 NULL
3 1001 NULL
4 1001 NULL
5 1002 1
6 1002 NULL
7 1002 NULL
8 1003 1
9 1004 1
10 1004 NULL
The result column basically selects 1 only for distinct Name values.
This should be some basic query, but I cannot figure it.
Since ordering will wreak havoc with your concept, I'll assume that you'll always sort by ID.
You can do something like this:
select ID, Name,
case (select count(*) from table t2 where t2.Name=t1.Name and t1.ID > t2.ID)
when 0 then 1
else null
end as Result
from table t1
This will count all the rows with the same name, and with a lower ID than the row processed. If there are no such rows, then it's a new name, so it'll get the 1, otherwise, it will get a null value.
You can use row_number to get the first instance of a group, in this case Name:
select ID, Name,
case row_number() over(partition by Name order by ID)
when 1 then 1 end Result
from YourTable
Try that
SELECT ID,
NAME,
Case When x.minId Is Not Null Then 1 Else Null End As Result
FROM Table
left JOIN (
SELECT Name, min(id) minId
FROM Table ) x
on x.minId = Table.Id
and x.Name = Table.Name

How do I use a select query to get the least of one value for each unique second value?

There are groups like this;
USER_ID SEQ_ID NAME
1 2 Armut
1 3 Elma
1 4 Kiraz
2 1 Nar
2 2 Uzum
4 3 Sheftali
4 4 Karpuz
4 5 Kavun
After select query I want to see only;
USER_ID SEQ_ID NAME
1 2 Armut
2 1 Nar
4 3 Karpuz
That is, I want the row with the least SEQ_ID for each USER_ID. What SQL query will give me this result?
Best regards
SELECT USER_ID, SEQ_ID, NAME
FROM table
WHERE NAME IN ('Armut', 'Nar', 'Karpuz')
ORDER BY USER_ID
If you have something else in mind, please clarify your question.
Looks to me like it should be:
SELECT USER_ID, MIN(SEQ_ID) AS SEQ_ID, NAME
FROM table
GROUP BY USER_ID, NAME
ORDER BY USER_ID;