SQL - WHERE (X, Y) IN (A, B) - sql

I have some kind of blockage currently.
My theoretic query looks something like this:
SELECT * FROM Table WHERE X in (a, b, c) AND Y IN (d, e, f)
So basically, I want all rows having multiple columns match, meaning:
X, Y
1, 2
3, 4
5, 6
7, 8,
9, 10
If I want to get all rows where (X=1, Y=2) or (X=5, Y=6), so X and Y are correlated, how would I do that?
(MS SQL2005+)

Why not something simple like the following?
WHERE (X = 1 AND Y = 2) OR (X = 5 AND Y = 6) ...
Or, if you're looking for rows (based on your example) where Y should be X + 1, then:
WHERE Y = X + 1
If you have thousands of OR clauses like the above, then I would suggest you populate a criterion table ahead of time, and rewrite your query as a join. Suppose you have such a table Criteria(X, Y) then your query becomes much simpler:
SELECT Table.*
FROM Table
INNER JOIN Criteria ON Table.X = Criteria.X AND Table.Y = Criteria.Y
Don't forget to add an index / foreign keys as necessary to the new table.
If for some reason you prefer to not create a table ahead of time, you can use a temporary table or table variable and populate it within your procedure.

If X and Y are in a table then a JOIN would be cleanest:
SELECT * FROM Table t
INNER JOIN XandY xy
WHERE tX = xy.X AND t.Y = xy.Y
If there not in a table I would strongly suggest putting them in one. IN only works with single-value sets and there's no way to line up results using multiple IN clauses.

Related

SQL logic to find/drop duplicates of column combination

Hi I have a sql query that results in the output like this
I want the output to look something like this:
Requirement:
row should not have duplicate when CONCATENATE(column one + column two) or CONCATENATE(column two +column one)
the duplicate value that is lower in column three is dropped
You can join the table with itself to find related pairs. Then discarding the unneeded ones becomes easier:
select x.*
from t x
left join t y on y.one = x.two and x.one = y.two
where y.one is null or x.one < y.one
EDIT:
If the values are coming from a query already you can reuse place it as a subquery of this one. For example
with t as (
-- your long query here
)
select x.*
from t x
left join t y on y.one = x.two and x.one = y.two
where y.one is null or x.one < y.one

PostgreSQL - left join generate_series() and table

I use generate series to create a series of numbers from 0 to 200.
I have a table that contains dirtareas in mm² in a column called polutionmm2. What I need is to left join this table to the generated series, but the dirt area must be in cm² so /100. I was not able to make this work, as I can't figure out how I can connect a table to a series that has no name.
This Is what I have so far:
select generate_series(0,200,1) as x, cast(p.polutionmm2/100 as char(8)) as metric
from x
left join polutiondistributionstatistic as p on metric = x
error: relation X does not exist
Here is some sample data: https://dbfiddle.uk/?rdbms=postgres_13&fiddle=3d7d851887adb938819d6cf3e5849719
what I would need, is the first column (x) counting all the way from 0 to 200, and where there is a matching value, to show it in the second column.
Like this:
x, metric
0, 0
1, 1
2, 2
3, null
4, 4
5, null
... , ...
... , ...
200, null
You can put generate_series() in the FROM. So, I think you want something like this:
select gs.x, cast(p.polutionmm2/100 as char(8)) as metric
from generate_series(0,200,1) gs(x) left join
p
on gs.x = (p.polutionmm2/100);
I imagine there is also more to your query, because this doesn't do much that is useful.

Can't get all of the data I want out of a join

I have a hive table that has some http sessions that I need to analyze. One column has a http session ID that is consistent throughout the entire session.
I'm trying find all rows that are part of sessions where one of a certain set of actions was performed AND the session ended in a timeout.
set hive.cli.print.header=true;
SELECT * FROM
(SELECT DISTINCT id, x_date, y
FROM log
WHERE ((to_date(x_date)) >= (date_sub(current_date, 1)))
AND y like '%timeout%') u
JOIN
(SELECT id, x_date, y, z, q, a
FROM log
WHERE ((to_date(x_date)) >= (date_sub(current_date, 1)))
AND z in ('1', '2', '3', '4')) o
ON u.id = o.id
ORDER BY u.id, o.x_date;
What I'm trying to find is all rows where
id = 123 and y like '%timeout%'
AND (id = 123 and z in('1','2','3','4')
What I am currently getting is something like
if (id = 123 and y like %timeout%)
select * where (id = 123 and z in ('1','2','3','4'))
The expected output should be much larger than the actual output, as I should get many lines that only has ID = 123.
The problem is I need this for all IDs that meet both criteria, so I have to actually find all of the IDs first :)
I hope this makes sense, I feel like I may have worded the question in a confusing manner.
Try this it would work in SQL, I'm not super versed in Hive, but it should work based on what I've read.
SELECT id, x_date, y, z, q, a
FROM log
WHERE z IN ('1','2','3','4','5')
AND id IN (
SELECT id
FROM log
WHERE ((to_date(x_date)) >= (date_sub(current_date, 1)))
AND y like '%timeout%')

Oracle: outer join(+) with or clause replacement

I have an enormous select that schematically looks like this:
SELECT c_1, c_2, ..., c_j FROM t_1, t_2, ..., t_k
WHERE e_11 = e_12(+)
AND e_21 = e_22(+)
AND ...
AND e_l1 = e_l2(+)
ORDER BY o
where j, k and l are in hundreds and e_mn is a column from some table. I need to add new columns A_1 and A_2 to the select from a new table T. The new columns are connected to the former select via a column call it B from a table R. I want those rows where A_1 = B or A_2 = B or those rows where there is no correspondeing A_i to the value B.
Suppose I only had to deal with tables T and R then I want this:
SELECT * FROM R
LEFT OUTER JOIN T
ON (A_1 = B OR A_2 = B)
To mimic this behaviour I'd want something like this in the big select:
SELECT c_1, c_2, ..., c_j, A_1, A_2 FROM t_1, t_2, ..., t_k, T
WHERE e_11 = e_12(+)
AND e_21 = e_22(+)
AND ...
AND e_l1 = e_l2(+)
AND (B = A_1(+) OR B = A_2(+))
ORDER BY o
this is, however, syntactically incorrect since the (+) operator cannot be used with the OR caluse. And if I leave out the (+)'s I lose those rows where there is no corresponding A_i to B.
What are my options here? Can I somehow find a way to do this without changing the whole body of the select? I doubt there is a reasonable way to do this, nevertheless I'd appreciate any help.
Thanks.

Recursive query rows to single column?

1) What are recursive queries ?
2) Are they dangerous ?
3) How can I make a recursive query to give me results from
ID Date
1 10/10/2010
1 20/10/2010
1 20/10/2010
2 11/10/2010
2 22/10/2010
to
ID Dates
1 10/10/2010,20/10/2010,20/10/2010
2 11/10/2010,22/10/2010
4) Can you explain how recursion operates inside the query? I googled but can't get how the recursion works actually. My database is DB2 ISeries V5R4.
Recursive query is a SQL query that can do a recursive computation. In other words, it can use the results of itself to continue query. Here is an abstract description:
1/ ancestor (x, y) = parent (x, y)
2/ ancestor (x, y) = parent (x, z) && ancestor (Z, Y).
It can be understood in a brief way that you to list all ancestor of Z, you list all of its parents and then all parents of those parents...
For example, if you have a table of Family with 2 columns Parent and Child like this:
pkey char 1 not null primary key
ckey char 1 not null primary key
('A','B')
('A','C')
('A','D')
('C','E')
('D','A')
('D','E')
('D','F')
('F','G')
The left handside is parent and the right hand side is children. Now you want to find all descedants of A then here is some code:
with parent_ctl (ckey) as
(
select ckey
from parents
where pkey='A'
UNION ALL
select c.ckey
from parents C, parent_ctl P
where P.ckey = C.Pkey
)
select ckey from parent_ctl;