how to combine Y or N or null values - sql

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

Related

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)

To pull 1 record out of multiple records having same data in a field based on other fields

A | B | C | D | E
a y 6 12 21
b n 3 10 5
c n 4 12 12
c n 7 12 2
c y 1 12 22
d n 6 10 32
d n 7 10 32
OUTPUT TABLE:
A | B | C | F
a y 6 21
b n 3 12
c y 1 22
d n 6 10
I have a table that contains certain fields. From that table I want to remove duplicate records in A and produce the output table.
Now, the field F is calculated based on the field C when there are no duplicates for the records in A. So, if there is only one record of a in A then if C>5 then the F Column(Output table) pulls the record in E column. So, if record b has the value <5 in field C, then the F column (output table) will pull the record in D column for b. I have been able to achieve this using a case statement.
However, when there are duplicate records in column A, I want only one of the records based on the column B. Only that record should be pulled that has the value 'y' in column B and where the column F contains the value from column E. If none of the duplicate records in A have a value of 'n' in the B column, then pull any record with column D as column F in the output table. I am not able to figure out this part.
Please let me know if anything is not clear.
Code I am using:
SELECT A,B,C,
CASE
WHEN (SELECT COUNT(*) FROM MyTable t2 WHERE t1.A=t2.A)>1
THEN (SELECT TOP 1 CASE WHEN b='y' THEN E ELSE D END
FROM MyTable t3
WHERE t3.A=t1.A
ORDER BY CASE WHEN b='y' THEN 0 ELSE 1 END)
ELSE {
case when cast(C as float) >= 5.00 then (Case when E = '0.00' then D else E end)
when cast(C as float)< 5.00 then D end )
}
END AS F
FROM MyTable t1
You might want to encapsulate this logic in a Function to make it look cleaner, but the logic would go like this:
IF the record count of rows in the table with the same value for A as the current row is greater than 1, THEN SELECT the TOP 1 record with this value for A ORDER BY CASE WHEN b='y' THEN 0 ELSE 1 END
Use another CASE WHEN b='y' to determine if you will use column E or D for output column F.
And ELSE (the record count is not greater than 1), use your existing CASE expression.
EDIT: Here is a more psuedo-codey explanation:
WITH cte AS (SELECT A,B,C,
ROW_NUMBER() OVER (PARTITION BY A, ORDER BY CASE WHEN b='y' THEN 0 ELSE 1 END) rn
FROM MyTable
)
SELECT A,B,C,
CASE
WHEN (SELECT COUNT(*) FROM MyTable t2 WHERE t1.A=t2.A)>1
THEN CASE WHEN b='y' THEN E ELSE D END
ELSE {use your existing CASE Expression}
END AS F
FROM cte t1
WHERE rn=1

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: How to count instances of Column A in Column B

I have a table with 2 columns A, and B that represent a connection graph between the two.
A B
1 3
2 5
4 2
3 5
2 3
I need to find how many instances of column A occur in column B (including 0)
So for the example above I would need the result set
A OccurencesInB
1 0
2 1
3 2
4 0
The best I have so far is
SELECT B, COUNT(*) AS TABLE_COUNT
FROM TABLE
GROUP BY B
ORDER BY TABLE_COUNT DESC
This does not find the instances of A that do not occur in B, which is crucial.
Any assistance will be greatly appreciated!
Use a correlated sub-query:
SELECT A,
TABLE_COUNT = (SELECT COUNT(*)
FROM TableName t2
WHERE t2.B = t1.A)
FROM TableName t1
GROUP BY A
ORDER BY TABLE_COUNT DESC, A
Result:
A TABLE_COUNT
3 2
2 1
1 0
4 0

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

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.