Comparing a particular column value for two rows in SQL - sql

I have a table as follows:
ID Version Type Value
121 1 A 100
121 1 B 200
122 2 A 300
122 2 B 300
123 3 A 300
123 3 B 300
124 4 A 420
124 4 B 420
121 3 A 410
121 3 B 410
I am trying to build a query which gives returns the rows where "Value" is different between Type A and Type B for same ID and Version.
For example, in the above scenario, ID and Version is Unique 5 times (121-1,122-2,123-3,124-4,121-3). I would look at "Type" for each unique group and compare "Value" for Type A and Type B.
The above scenario should return:
ID Version Type Value
121 1 A 100
121 1 B 200
The above two rows are the only ones with different "Value" for unique ID and Version and among Type A and Type B.
Any help will be greatly appreciated :)

You can use exixts :
select t.*
from table t
where exists (select 1
from table t1
where t1.id = t.id and
t1.Version = t.Version and
t1.type <> t.type and
t1.Value <> t.Value
);

You can join a table to itself:
SELECT *
FROM [MyTable] t0
INNER JOIN [MyTable] t1 ON t1.ID = t0.ID AND t0.Type <> t1.Type AND t0.Value <> t1.Value
or
SELECT *
FROM [MyTable] t0
INNER JOIN [MyTable] t1 ON t1.ID = t0.ID AND t1.Type = 'B' AND t0.Value <> t1.Value
WHERE t0.Type = 'A'

If you have only two types, I am going to recommend a different result set format:
select id, version,
max(case when type = 'A' then value end) as value_a,
max(case when type = 'B' then value end) as value_b
from t
where type in ('A', 'B')
group by id, version,
having max(case when type = 'A' then value end) <> max(case when type = 'B' then value end);
I recommend this because a typical follow-on question might be "how big is the difference".

This is one way to approach this problem:
select *
from t1
where (id, value, version) in (select id, value, version
from t1
group by id, value, version
having count(id) = 1);
Here is a DEMO

This is what I ended up doing:
SELECT MAX(Value), MIN(Value)
FROM table_name
GROUP BY ID, Version
HAVING MAX(Value)<>MIN(Value);

Related

Find the 2nd row of data based on a column value, if not available then print NULL

I am working on some project in hive and below problem is one part of it. Please note that i am going to apply the solution for this query on a subquery result /table which i have already made.
So as part of this, i am trying to print the row for each id based on column value of rnum. If rnum=2 then print both the column values, i.e., id,value. If rnum= 2 is not present for an id then then print id,'No value'.
Give below sample input and expected output.
For eg.
for id 100, since rnum is only 1, hence print value as 'No value'
for id 200, print only value for rnum=2, i.e., xyz and ignore value for rnum=1,3 and 4
Input:
id value rnum
100 abc 1
200 def 1
200 xyz 2
200 rtz 3
200 tgv 4
Expected output:
id value
100 No Value
200 xyz
You can use aggregation and case logic:
select id,
(case when sum(case when mum = 2 then 1 else 0 end) > 0
then max(case when mum = 2 then value end)
else 'No Value'
end)
from t
group by id;
You can do it as shown below:
select a.id, case when t.id is null then 'No value' else t.value end
from (select distinct id as id from t) a
left join t on t.rnum = 2 and a.id = t.id
Here's your query.
select t1.id, case when t2.rnum != 1 then t2.value else 'no value' end
from (
select count(1) as ct, id from test2
group by id) t1
left join test2 t2 on t2.id = t1.id and t2.rnum = 2
order by t1.id asc
Changed, allowing for any id values:
with t2(id, cnt) as
(
select id, count(*) as cnt
from t1
group by id
)
select t1.id,
max(case
when t2.cnt = 1 and t1.rnum = 1 then 'No Value'
when t2.cnt > 1 and t1.rnum = 2 then value
end)
from t1
join t2 on t2.id = t1.id
group by t1.id

How to select unique value from two columns if third have the same value

TABLE:
id second_id status
1 2 1
2 1 0
1 3 1
3 1 1
1 4 1
4 1 1
I try to select only this unique value where the pair have the same status
OUTPUT:
id second_id status
1 3 1
1 4 1
I try with
SELECT table.id, table.second_id, table.status FROM table
WHERE table.id = 1 and table.status = 1
but this return of course bad results ;)
Thx for help :)
One way to do this is to JOIN the table to itself, looking for matching id and second_id values with the same status. We also check that the second table's id value is greater than the first to avoid duplicates:
SELECT t1.*
FROM test t1
JOIN test t2 ON t2.id = t1.second_id
AND t2.second_id = t1.id
AND t2.status = t1.status
AND t2.id > t1.id
Output:
id second_id status
1 3 1
1 4 1
Demo on dbfiddle
One method uses exists:
select t.*
from t
where exists (select 1
from t t2
where t2.second_id = t.id and
t2.id = t.second_id and
t2.status = t.status
);
Or, expressing this using in and tuples is simpler:
select t.*
from t
where (id, second_id, status) in
(select second_id, id, status from t);

SQL Join different item from one table

I have a table
Tablename = table01
ID Item value
4 a 10
5 b 12
5 c 15
and my sql
select value as b from table01 where ID = 5 and Item = b
select value as c from table01 where ID = 5 and Item = c
How can i join this two sql?
this is my imagine result
b c
12 15
Here is one method:
select t1.id, t1.value as b, t2.value as c
from table1 t1 join
table1 t2
on t1.id = t2.id and t1.item = 'b' and t2.item = 'c';
SELECT MAX( CASE WHEN Item = 'b' THEN value END ) AS b,
MAX( CASE WHEN Item = 'c' THEN value END ) AS c
FROM table01;
Here is one way using Conditional Aggregate
select max(case when Item = 'b' then value end),
max(case when Item = 'c' then value end)
from yourtable
Where ID = 5
and Item in ( 'b' , 'c')
Note : This considers that ID & ITEM combination is not duplicated. If it is duplicated then you will max value out of duplicate

Union three tables and show where data came from

have no idea how to solve following:
There are three tables each with a column of names, for example
Table 1 - column name 'Name' - values 'A', 'B' and 'C'
Table 2 - column name 'Name' - values 'A' and 'B'
Table 3 - column nane 'Name' - values 'A' and 'C'
The goal is to UNION the tables - each value of the three tables should be shown only one time. In addition there should be three new "virtual columns" showing in which table the value is included('1' when value is included, '0' if not). So the result should look like this:
Value | Table1 | Table2 | Table3
--------------------------------
A | 1 | 1 | 1
B | 1 | 1 | 0
C | 1 | 0 | 1
Hope someone can help me, thanks in advance.
Does this do what you want?
select Name, max(Table1) as Table1, max(Table2) as Table2, max(Table3) as Table3
from (select Name, 1 as Table1, 0 as Table2, 0 as Table3
from table1
union all
select Name, 0 as Table1, 1 as Table2, 0 as Table3
from table2
union all
select Name, 0 as Table1, 0 as Table2, 1 as Table3
from table3
) t
group by Name;
You might want to use sum() instead of max() to get the number of times the value occurs in each table.
If your db supports full joins you can try the query below.
select
coalesce(t1.Name,t2.Name,t3.Name) myValue,
(case when max(t1.Name) is not null then 1 else 0 end) c1,
(case when max(t2.Name) is not null then 1 else 0 end) c2,
(case when max(t3.Name) is not null then 1 else 0 end) c3
from
Table1 t1
full join Table2 t2 on t1.Name = t2.Name
full join Table3 t3 on t1.Name = t3.Name
group by coalesce(t1.Name,t2.Name,t3.Name)
If you know that a value will not appear more than once in each table, you can remove the group by and max parts.
Here's my attempt (update: works f.e. in SQL-Server 2005 and upwards due to the CTE):
With names AS
(
SELECT Name, Source = 'T1'
FROM dbo.Table1
UNION ALL
SELECT Name, Source = 'T2'
FROM dbo.Table2
UNION ALL
SELECT Name, Source = 'T3'
FROM dbo.Table3
)
SELECT n.Name,
Table1 = CASE WHEN EXISTS
(SELECT 1 FROM names n2
WHERE Source = 'T1' AND n2.Name=n.Name)
THEN 1 ELSE 0 END,
Table2 = CASE WHEN EXISTS
(SELECT 1 FROM names n2
WHERE Source = 'T2' AND n2.Name=n.Name)
THEN 1 ELSE 0 END,
Table3 = CASE WHEN EXISTS
(SELECT 1 FROM names n2
WHERE Source = 'T3' AND n2.Name=n.Name)
THEN 1 ELSE 0 END
FROM names n
GROUP BY n.Name
Demo

SQL: Outputting Multiple Rows When Joining From Same Table

My question is this: Is it possible to output multiple rows when joining from the same table?
With this code for example, I would like it to output 2 rows, one for each table. Instead, what it does is gives me 1 row with all of the data.
SELECT t1.*, t2.*
FROM table t1
JOIN table t2
ON t2.id = t1.oldId
WHERE t1.id = '1'
UPDATE
Well the problem that I have with the UNION/UNION ALL is this: I don't know what the t1.oldId value is equal to. All I know is the id for t1. I am trying to avoid using 2 queries so is there a way I could do something like this:
SELECT t1.*
FROM table t1
WHERE t1.id = '1'
UNION
SELECT t2.*
FROM table t2
WHERE t2.id = t1.oldId
SAMPLE DATA
messages_users
id message_id user_id box thread_id latest_id
--------------------------------------------------------
8 1 1 1 NULL NULL
9 2 1 2 NULL 16
10 2 65 1 NULL 15
11 3 65 2 2 NULL
12 3 1 1 2 NULL
13 4 1 2 2 NULL
14 4 65 1 2 NULL
15 5 65 2 2 NULL
16 6 1 1 2 NULL
Query:
SELECT mu.id FROM messages_users mu
JOIN messages_users mu2 ON mu2.latest_id IS NOT NULL
WHERE mu.user_id = '1' AND mu2.user_id = '1' AND ((mu.box = '1'
AND mu.thread_id IS NULL AND mu.latest_id IS NULL) OR mu.id = mu2.latest_id)
This query fixes my problem. But it seems the answer to my question is to not use a JOIN but a UNION.
You mean one row for t1 and one row from t2?
You're looking for UNION, not JOIN.
select * from table where id = 1
union
select * from table where oldid = 1
If you are trying to multiply rows in a table, you need UNION ALL (not UNION):
select *
from ((select * from t) union all
(select * from t)
) t
I also sometimes use a cross join to do this:
select *
from t cross join
(select 1 as seqnum union all select 2) vals
The cross join is explicitly multiplying the number of rows, in this case, with a sequencenumber attached.
Well, since it's the same table, you could do:
SELECT t2.*
FROM table t1
JOIN table t2
ON t2.id = t1.oldId
OR t2.id = t1.id
WHERE t1.id = '1'