PLSQL or SSRS, How to select having all values in a group? - sql

I have a table like this.
ID NAME VALUE
______________
1 A X
2 A Y
3 A Z
4 B X
5 B Y
6 C X
7 C Z
8 D Z
9 E X
And the query:
SELECT * FROM TABLE1 T WHERE T.VALUE IN (X,Z)
This query gives me
ID NAME VALUE
______________
1 A X
3 A Z
4 B X
6 C X
7 C Z
8 D Z
9 E X
But i want to see all values of names which have all params. So, only A and C have both X and Z values, and my desired result is:
ID NAME VALUE
______________
1 A X
2 A Y
3 A Z
6 C X
7 C Z
How can I get the desired result? No matter with sql or with reporting service. Maybe "GROUP BY ..... HAVING" clause will help, but I'm not sure.
By the way I dont know how many params will be in the list.
I realy appreciate any help.

The standard approach would be something like
SELECT id, name, value
FROM table1 a
WHERE name IN (SELECT name
FROM table1 b
WHERE b.value in (x,y)
GROUP BY name
HAVING COUNT(distinct value) = 2)
That would require that you determine how many values are in the list so that you can use a 2 in the HAVING clause if there are 2 elements, a 5 if there are 5 elements, etc. You could also use analytic functions
SELECT id, name, value
FROM (SELECT id,
name,
value,
count(distinct value) over (partition by name) cnt
FROM table1 t1
WHERE t1.value in (x,y))
WHERE cnt = 2

I prefer to structure these "sets within sets" of queries as an aggregatino. I find this is the most flexible approach:
select t.*
from t
where t.name in (select name
from t
group by name
having sum(case when value = 'X' then 1 else 0 end) > 0 and
sum9case when value = 'Y' then 1 else 0 end) > 0
)
The subquery for the in finds all names that have at least one X value and one Y value. Using the same logic, it is easy to adjust for other conditions (X and Y and Z,; X and Y but not Z and so on). The outer query just returns all the rows instead of the names.

Related

Merge two tables and chain id fields in order

I'm looking for a way to merge two tables (or more) and modify/order their numeric id. To put it simply here is what I want to do schematically :
Table example 1 :
Id
Field
4
x
1
x
5
x
3
x
2
x
Table example 2 :
Id
Field
1
x
3
x
5
x
2
x
4
x
Expected result (modify table 1 as 1-2-3-4-5 and table 2 as 6-7-8-9-10 THEN order both id by asc)
Id
Field
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
x
10
x
I was aiming for a union tables nested in a select row_number() over (order by id) but I don't really know how to modify table 2 as 6-7-8-9-10 before
Try using this example:
SELECT id, Field FROM t1
UNION ALL
SELECT (SELECT MAX(id) FROM t1) + ROW_NUMBER() OVER (ORDER BY id) AS id, Field
FROM t2
ORDER BY id
fiddle

How can I select rows corresponding to the unique pair of column values with the highest value of another column in PostgreSQL?

My table looks like this:
A
B
X
1
1
1
1
1
2
1
1
3
1
2
1
1
2
2
2
2
1
2
2
2
2
2
3
I need to select the row with the highest value in X column for each unique A, B pair.
The result would be:
A
B
X
1
1
3
1
2
2
2
2
3
I would recommend distinct on:
select distinct on (a, b) t.*
from t
order by a, b, x desc;
This allows you to select other columns from the rows, other than a, b, and x.
With an index on (a, b, x desc), this would typically be the fastest solution.
You can use the MAX aggregate function as follows:
select A, B, MAX(X) AS X
from YOUR_TABLE
group by A, B
That would work like that:
select * from a where x = (select max(x) from a)

convert cell value to respective column in PostgreSQL

Here's the sample:
select * from tmp
--output
A B Value
---------------------
a x 1
b x 2
a y 3
b y 4
c y 5
After a SQL command grouping on B column, I'd like to make each value of column A to be a separate column as illustrated below:
B a b c
----------------------------
x 1 2 null
y 3 4 5
If there any specific terminology for this transformation? Thanks!
You need to find max of other value and group it by with anchor column(b in your case). Please note that your column count should be similar to number of values expected in field A.
select b,
max(case when A='a' then Value else null end)a,
max(case when A='b' then Value else null end)b,
max(case when A='c' then Value else null end)c
from tmp
group by 1

SQL query: same rows

I'm having trouble finding the right sql query. I want to select all the rows with a unique x value and if there are rows with the same x value, then I want to select the row with the greatest y value. As an example I've put a part of my database below.
ID x y
1 2 3
2 1 5
3 4 6
4 4 7
5 2 6
The selected rows should then be those with ID 2, 4 and 5.
This is what I've got so far
SELECT *
FROM base
WHERE x IN
(
SELECT x
FROM base
HAVING COUNT(*) > 1
)
But this only results in the rows that occur more than once. I've added the tags R, postgresql and sqldf because I'm working in R with those packages.
Here is a typical way to formulate the query in ANSI SQL:
select b.*
from base b
where not exists (select 1
from base b2
where b2.x = b.x and
b2.y > b.y
);
In Postgres, you would use distinct on for performance:
select distinct on (x) b.*
from base b
order by x, y desc;
You could try this query:
select x, max(y) from base group by x;
And, if you'd also like the id column in the result:
select base.*
from base join (select x, max(y) from base group by x) as maxima
on (base.x = maxima.x and base.y = maxima.max);
Example:
CREATE TABLE tmp(id int, x int ,y int);
INSERT INTO .....
test=# SELECT x, max(y) AS y FROM tmp GROUP BY x;
x | y
---+---
4 | 7
1 | 5
2 | 6

how to combine Y or N or null values

still not found the solution described in update 2
thx for help
ill try to explain my issue with my poor english. hope someone can solve my problem.
i got the following table
A B
1 Y
2 null
3 Y
what result i want?
in dependency of the rank in column A i want to combine column B.
the result in that example is ... no result
the reason is because there is a null in rank 2 and the next and the last rank (=3) has a value (=Y).
next example
A B
1 Y
2 null
3 null
result i want is
A B
1 Y
because the way after is free... means 2 and the last 3 has null
another example
A B
1 null
2 N
3 null
again no result is what i want in this case. because first =1 has null value.
i try now to conclude ... if n(e.g. 2) of column B has value Y or N then the elements bevor (in this 1) must have the value Y or N.
thank you very much. i tried different technics without any success...
UPDATE 1
thank you fast comment
some example dates with expected result
example 1
A B
1 Y
2 N
3 null
4 null
expected result
A B
2 N
example 2
A B
1 N
2 Y
3 N
4 null
expected result
A B
3 N
example 3
A B
1 null
2 Y
3 Y
4 null
expected result
no result
example 4
A B
1 Y
2 Y
3 null
4 Y
expected result
no result
UPDATE 2
forget the basic case
A B
1 Y
2 N
3 Y
expected result
A B
3 N
Establish the highest value of A where B is Y or N, and the lowest value of A where B is null. Provided the first value is lower than the second value you have a valid result set.
select yt.A
, yt.B
from
( select max(case when B is not null then A else null end) as max_b_yn
, min(case when B is null then A else null end) as min_b_null
from your_table ) t1
, your_table yt
where ( t1.min_b_null is null
or t1.max_b_yn < t1.min_b_null )
and yt.A = t1.max_b_yn
/
I think you want the last row before the first NULL. If this is correct, then the following gets what you want:
select t.*
from t join
(select min(A) as NullA from t where B is NULL) t2
on t.A = t2.NullA - 1
Ah, I see. To get the last row with an "N":
select t.*
from t
where t.A in (select max(A) as MaxA
from t join
(select min(A) as NullA from t where B is NULL) t2
on t.A < t2.NullA
where t.B = 'N'
)
OK, I think I have what you need. It grabs the last row that has a value in column B as long as there isn't a row with a NULL that precedes it.
select MAX(A), B
from table_a
where B IS NOT NULL
and table_a.A > (
select MIN(A)
FROM table_a
WHERE B IS NULL
)
Group by B
select top 1 A, B
from #Temp
where B is not null
order by A desc
or
select top 1 A, B
from #Temp
where B = 'N'
order by A desc