select from table where both id exist - sql

I need to select from a single table where both id exists in the column having matching id in another column.
My query is like below which gives rows with even just single matching id.
select * from customer_appdata where appdata_id in(11,12)
id customer_id appdata_id
6 65 4
7 65 12
8 65 8
9 66 11
10 66 12
so here i just want last and second last rows(9,10) as they have both 11 and 12 with common id 66.

If I understand the problem correctly, this should work:
select * from customer_appdata where customer_id in (
select customer_id from customer_appdata
where appdata_id in (11,12)
group by customer_id
having count(distinct appdata_id) = 2
)
You find all customer_ids that are repeated specific number of times (that's the inner query) and then select all rows with those customer_ids. There is probably a faster way, but if performance is not critical this is a simple way to solve the problem.

This query selects rows with customer_appdata of 12 or 11 and uses exists to see if the other row is also in the table.
select * from customer_appdata c1
where appdata_id in (11,12)
and exists (
select 1 from customer_appdata c2
where c2.appdata_id in (11,12)
and c2.appdata_id <> c1.appdata_id
and c2.customer_id = c1.customer_id
)

Related

SQL query: Get rows where column A not exists with same value and column value B

Sorry, for the confusing title, but did not found a better one. Here is the situation:
CREATE TABLE orders (
order_id int NOT NULL,
company_id int NOT NULL,
last_update date NULL
)
Table Data:
ORDER_ID COMPANY_ID LAST_UPDATE
1 1 2020/06/08
2 1 2020/06/08
3 1 2020/06/08
4 2 2020/06/08
5 2 2020/01/27
6 3 2020/06/08
7 3 2020/06/08
8 3 2020/06/08
9 3 NULL
10 4 2020/06/08
11 4 2020/06/08
12 4 2020/06/08
13 4 2020/06/08
14 4 2020/06/08
I want to have all rows, with a company, where there is no row with the same company and a LAST_UPDATE older than 3 months (or null).
What does not work:
I cannot use a simple WHERE clause with the date, because this filters me out just the rows 5 and 9. I only want the rows 1-3 & 10-14.
What works, but is to slow:
I can use a subquery (AND company_ID NOT IN (SELECT DISTINCT company_id [...])), but this completely kills my performance. In prod environment I have nearly 50M rows, the ResultSet of the subquery is too huge.
My current workaround:
I just ordered my results by company_id, last_update and use a "continue" in my Java Code, if there is a too old last_update. But that's also not optimal.
Question:
Is there are performant SQL only way, to achive this. Maybe over a "group by ... having" - clause.
Thanks in advance!
You could use window functions:
select o.*
from (select o.*, min(last_update) over (partition by company_id) as min_last_update
from orders o
) o
where min_last_update >= add_months(sysdate, -3);
But a simple not exists should also be fine:
select o.*
from orders o
where not exists (select 1
from orders o2
where o2.company_id = o.company_id and
o2.last_update < add_months(sysdate, -3)
);
Either of these can take advantage of an index on orders(company_id, last_update).
You can use the WINDOW functions as follows:
SELECT T.* FROM (
SELECT T.*,
MIN(CASE WHEN LAST_UPDATE IS NULL THEN LAST_UPDATE - 100
ELSE LAST_UPDATE END) OVER(
PARTITION BY T.COMPANY_ID
) AS MIN_LAST_UPDATE
FROM ORDERS T ) T
WHERE T.MIN_LAST_UPDATE >= ADD_MONTHS(SYSDATE, - 3);

is possible to see a previous row after a selected one?

i have created a table like this
create table numbers(
first int ...
second int...
third int ...
fourth ....
fifth int..
sixt int ...
id primary key..
...);
every sextain has an id for identification.
i would like to see a previuous row of the one i selected
example
select * from numbers where first=6 And second=54;
as output (we will have all the numbers were first and second are 6 and 54 with id)
first second 3 4 5 6 id
6 54 10 11 13 66 10
6 54 7 8 9 10 520
i would like too see row 9 and row 519 is there a way to see those? i know i
could do
select * from numbers where id=9;
select * from nbumbers where id= 519;
but i have 50-60 row it's impossible to do
individually one by one.
you can use
SELECT * FROM NUMBERS WHERE ID IN
(SELECT ID -1 FROM NUMBERS WHERE first = 6 and second = 54);
You can use lead():
select n.*
from (select n.*,
lead(first) over (order by id) as next_first,
lead(second) over (order by id) as next_second
from numbers n
) n
where next_first = 6 and next_second = 54;
Another method would use a cumulative sum:
select n.*
from (select n.*,
max(case when first = 6 and second = 54 then id end) over
(order by id
rows between unbounded preceding and 1 preceding
) as prev_id
from numbers n
) n
where prev_id = id;
You probably want:
select
n.*
from (
select * from numbers where first = 6 and second = 54
) x
join numbers n on n.id = x.id - 1

select query - eliminate rows with duplicate column value on condition

I have a select query that ends up with results like:
ID COMPLIANT
------------------
10 0
12 0
29 0
29 1
43 1
44 1
44 0
How can I get results without these duplicate ID rows, on the condition that if an ID has already been marked as COMPLIANT once (a 1 instead of a 0), the duplicate rows with COMPLIANT=0 do not appear? I'd want:
ID COMPLIANT
------------------
10 0
12 0
29 1
43 1
44 1
How about aggregation?
select id, max(complaint) as complaint
from t
group by id;
This returns one row per id. If you can have multiple complaints -- and you want all of those -- than an alternative is:
select id, complaint
from t
where complaint = 1
union all
select id, complaint
from t
where not exists (select 1 from t t2 where t2.id = t.id and t2.complaint = 1);
this will work:
select id, max(complaint)
from tablename
group by id;

MSSQL - Grouping Results using MAX()

I have this dataset;
dID Num
11 3
11 4
11 5
13 9
13 11
45 3
45 8
99 44
99 78
99 53
I want it to look like this.
dID Num
11 5
13 11
45 8
99 78
List all ID's and only show those ID's where the 'Num' is the Largest number for that group of ID's
my attempt here doesnt quite work out.
http://sqlfiddle.com/#!9/1a47f/1
You seem to just want an aggregation query:
select dId, max(num) as num
from data t
group by dId;
You need to aggregate by the first column, not the argument to the aggregation function.
If you have oversimplified the problem, and want other columns as well, then use row_number():
select t.*
from (select t.*, row_number() over (order by num desc) as seqnum
from data t
) t
where seqnum = 1;
You almost get it right, you just grouped by the wrong column:
select dID,
MAX(num) from data
group by dID
See it here: http://sqlfiddle.com/#!9/1a47f/3

SQL Server Group by clause - Simple stuff

I have a table with questions and answers and sessionid.
Sometimes the same person (sessionid) will answer the same question more than 1 time, and that gets stored in the table.
The qapp_answer table content looks something like this:
Id, SessionID, QNumber, Qanswer
72 11 1 3
73 11 1 4
74 11 2 1
75 11 2 3
76 11 3 1
So, I only want each Qnumber to be displayed one time (so 3 rows in total), and basically just use their latest answer for display (Qanswer).
This is the code so far:
select Qnumber, Qanswer
from qapp_answers
where sessionid = 11
group by QNumber, Qanswer
And it returns 5 rows.
Should be simple, but i havent used SQL for years.
You can basically use ROW_NUMBER() which generates sequential number based on the group specified. The query belows group the records by QNumber and generates sequential number sorted by ID in descending order. The latest ID for every group has the value of 1 so you need to filter out records that has a generated value of 1.
SELECT ID, SessionID, QNumber, Qanswer
FROM
(
SELECT ID, SessionID, QNumber, Qanswer,
ROW_NUMBER() OVER (PARTITION BY QNumber ORDER BY ID Desc) rn
FROM tableName
WHERE SessionID = 11
) a
WHERE a.rn = 1
SQLFiddle Demo