Finding a pair of row in SQL - sql

I am very confused how to define the problem statement but Let's say below is table History i want to find those rows which have a pair.
Pair I will defined like column a and b will have same value and c should have False and d should be different for both row.
If I am using Java i would have set row 3, C column as true when i hit a pair or would have saved both row 1 and row 3 into different list. So that row 2 can be excluded. But i don't know how to do the same functionality in SQL.
Table - History
col a, b, c(Boolean ), d
1 bb F d
1 bb F d
1 bb F c
Query ? ----
Result - rows 1 and 3.

Assuming the table is called test:
SELECT
*
FROM
test
WHERE id IN (
SELECT
MIN(id)
FROM
test
WHERE
!c
AND a = b
AND d != a
GROUP BY a, d
)
We get the smallest id of every where matching your conditions. Furthermore we group the results by a, d which means we get only unique pairs of "a and d". Then we use this ids to select the rows we want.
Working example.
Update: without existing id
# add PK afterwards
ALTER TABLE test ADD COLUMN id INT PRIMARY KEY AUTO_INCREMENT FIRST;
Working example.

All the rows match the conditioin you specified. A "pair" happens when:
column a and b will have same value, and
c should have False, and
d should be different for both rows.
1 and 3 will match that as well as 2 and 3. Also, 3 and 1 will match as well as 3 and 2. There are four solutions.
You don't say which database, so I'll assume PostgreSQL. The query that can search using your criteria is:
select *
from t x
where exists (
select null from t y
where y.a = x.a
and y.b = x.b
and not y.c
and y.d <> x.d
);
Result:
a b c d
-- --- ------ -
1 bb false d
1 bb false d
1 bb false c
That is... the whole table.
See running example at DB Fiddle.

Related

SQL: select rows from a certain table based on conditions in this and another table

I have two tables that share IDs on a postgresql .
I would like to select certain rows from table A, based on condition Y (in table A) AND based on Condition Z in a different table (B) ).
For example:
Table A Table B
ID | type ID | date
0 E 1 01.01.2022
1 F 2 01.01.2022
2 E 3 01.01.2010
3 F
IDs MUST by unique - the same ID can appear only once in each table, and if the same ID is in both tables it means that both are referring to the same object.
Using an SQL query, I would like to find all cases where:
1 - the same ID exists in both tables
2 - type is F
3 - date is after 31.12.2021
And again, only rows from table A will be returned.
So the only returned row should be:1 F
It is a bit hard t understand what problem you are actually facing, as this is very basic SQL.
Use EXISTS:
select *
from a
where type = 'F'
and exists (select null from b where b.id = a.id and dt >= date '2022-01-01');
Or IN:
select *
from a
where type = 'F'
and id in (select id from b where dt >= date '2022-01-01');
Or, as the IDs are unique in both tables, join:
select a.*
from a
join b on b.id = a.id
where a.type = 'F'
and b.dt >= date '2022-01-01';
My favorite here is the IN clause, because you want to select data from table A where conditions are met. So no join needed, just a where clause, and IN is easier to read than EXISTS.
SELECT *
FROM A
WHERE type='F'
AND id IN (
SELECT id
FROM B
WHERE DATE>='2022-01-01'; -- '2022' imo should be enough, need to check
);
I don't think joining is necessary.

Get rows which don't satisfy any of below condition

I have a table with id and different values. I want to have my output something which would looks like this
id value
----------
1 t
1 f
2 t
3 f
4 f
4 f
Expected output
id value
---------
3 f
4 f
If we look at the output, my condition here to check if my id has all f as value then return f, if it has all t then don't, and if any one of the id has t also don't include row in output.
How to achieve this ?
create subquery and exclude the values accordingly. i think hiveql supports where clause subqueries.
select id, value
from your_data_source
where id not in
(select id from your_data_source where value='t' group by id)
group by id, value

SQL Updated question conditional division

Given columns A and B from Table1:
A B
Small 3
Med 4
Med 1
Large 2
Small 1
Given columns S, M, L from Table2:
S M L
5 5 3
8 2 1
4 6 5
2 2 8
I want to create a new column in Table1 that outputs the quotients of values of column B and Avg(Table2.S) only if the entry in the same row in column A of is 'Small'. If column A has 'Med', we divide by Avg(Table2.M) and if it has 'Large', we divide by Avg(Table2.L). It would continue to check this row by row. For example, in the first row of column B, we have '3', and on the same row in column A, we have 'Small', so we would output 0.6316 (3/Avg(Table2.S)). So the expected column, let's call it C, would be:
C
0.6316
1.0667
0.2667
0.4076
0.2105
How would I output C using MS Access SQL? I tried
Select
Switch(Table1.A ='Small', Table1.B/Avg(Table2.S),
Table1.A ='Med', Table1.B/Avg(Table2.M),
Table1.A ='Large', Table1.B/Avg(Table2.L))
From Table1, Table2
but I usually get an error that says my query doesn't include the specified expression as an aggregate function.
Here is a way to do this
select A,B,switch(A="Small",x.avg_s,A="Med",avg_m,A="Large",avg_l) as avg_vals,B/switch(A="Small",x.avg_s,A="Med",avg_m,A="Large",avg_l)
from table1 y,
(select avg(S) as avg_s,avg(M) as avg_m,avg(L) as avg_l
from table2
)x
The output is

Different conditions (similiar to IF) + uniqe values

i need to filter data using different conditions. One is that I need to queck if the values in one column (column d) are unique IF the values in another column (c) are greater than 1.
Lets assume:
Column a, b, c, d
So I don't want any entries, where c is greater than 1 while d has non unique values.
Select TOP 100 * From table
Where (a = 'Max' AND b = '2019') -- just an additional filter, which always applies
AND (c = 1 -- if c is one, that is fine
OR (c > 1 AND -- here I want to check if c is bigger than 1 AND if d is unique; but thats the part I need help with
);
Thank you very much in advance!
Create a CTE where you count the distinct values of column d and use it in the WHERE clause:
with cte as (
select count(distinct d) counter from tablename
)
...........................................
Where ....(c > 1 AND (select counter from cte) = 1)

ladder-like record selection without looping

I have a table like this, A and B as columns:
A B
1 0
2 1
3 2
4 3
A record can be selected by defining a value for A. If the selected row has a value for B, the row whose A's value is equal to the record's B must also be selected, and if that selected record has a B it must again be selected and so on.
Example:
If the user queries for A = 3, the returned rows must be:
A B
3 2
2 1
1 0
This is the output because of this condition: A3 has a value for B; there is a record whose A is equal to the first row's B which is 2 and the second record's B is 1 which still has a matching record.
Is there a way this can be done without looping through the records?
You can use recursive CTE to achieve this:
http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx
;WITH RCTE AS
(
SELECT * FROM Table1 WHERE A = 3
UNION ALL
SELECT t.* FROM RCTE r
INNER JOIN Table1 t ON r.B = t.A
)
SELECT * FROM RCTE
SQLFiddle DEMO