Query Selecting Row when using distinct - sql

I would like to do the following.
Lets say the data looks somthing like this
Number letter
1 b
1 c
1 a
2 d
2 b
2 c
3 a
3 b
3 c
I want to filter the data in the folowing way column number to get all the distinct numbers and then also filter out the letter d
The output should be as follows
Number letter
1
2
2 d
3
Would this be possible?
I can do this in two table but i would like to know if it was possible to combine it into one
thank you
Chris

This should do it:
select distinct number, case when letter = 'd' then 'd' end letter from mytable
In Oracle you can use decode to shorten the query:
select distinct number, decode(letter, 'd', 'd') letter from mytable

How about union all?
select distinct number, null as letter
from t
union all
select number, 'd'
from t
where letter = 'd';

Related

How can I select if row contains a specific type, not contains select existing row

I have a table below. There are 3 types(A,B,C) available. I want to create general a Sql query. If row has type B or type C, the row with type B or C should be listed. If row has just type A, the row with type A should be listed.
Table;
Number
Type
1
A
1
B
2
A
3
A
3
C
4
A
5
A
6
A
6
B
6
C
Expected result when the query run;
Number
Type
1
B
2
A
3
C
4
A
5
A
6
B
6
C
How can I create the query? Thank you in advance for your help.
I would assign each type a precedence, and only return the types of the highest precedence.
Where two types can be the same precedence (because you want to return both), RANK() (rather than ROW_NUMBER()) will ensure both are assigned the same value.
WITH
precedence AS
(
SELECT
*,
RANK()
OVER (
PARTITION BY Number
ORDER BY CASE Type WHEN 'C' THEN 2
WHEN 'B' THEN 2
WHEN 'A' THEN 1
ELSE 0
END
DESC
)
AS row_precedence
FROM
your_table
)
SELECT
*
FROM
precedence
WHERE
row_precedence = 1
One option to make it a little neater could be to use APPLY (or a join on a lookup table) to derive the integers outside of the window function's code...
WITH
precedence AS
(
SELECT
*,
RANK()
OVER (
PARTITION BY Number
ORDER BY type_precedence.value DESC
)
AS row_precedence
FROM
your_table
CROSS APPLY
(
SELECT
CASE Type WHEN 'C' THEN 2
WHEN 'B' THEN 2
WHEN 'A' THEN 1
ELSE 0
END
AS value
)
AS type_precedence
)
SELECT
*
FROM
precedence
WHERE
row_precedence = 1
Demo: https://dbfiddle.uk/2Abwpa8p

UNION - inconsistent datatype got CLOB

I have a table that look like this
name
value
a
1
b
2
c
3
Of course not with these datas, but I will use it as an example
I need to use it as a inner join, where I can have each name as a column.
It is a defined amount of rows, so that should not be a problem
I have tried to do it as
SELECT
value AS a,
NULL as b
FROM ex
WHERE name = 'a'
UNION
SELECT
NULL as a,
value AS b
FROM ex
WHERE name = 'b'
And so on, but I get the error ORA-00932: inconsistent datatypes: expected - got CLOB
I have also tried with
SELECT
CASE WHEN name = 'a' THEN value ELSE NULL END AS a,
CASE WHEN name = 'b' THEN value ELSE NULL END AS b
FROM ex
WHERE name IN ('a', 'b')
But the result from this is of course
a
b
1
NULL
NULL
2
But I need to eliminate the NULL values, so I only have one row like
a
b
1
2
Does anybody have a good idea of how to solve this problem?
I can of course make 4 joins, but I was thinking, if it could be done in one join, as that will possibly be faster than look in the same table 4 times
I have the impression that you just want to get the value per name. Is this what you aim for:
WITH dat AS
(
SELECT 'a' AS NAME, 1 AS VALUE FROM dual UNION ALL
SELECT 'b', 2 FROM dual UNION ALL
SELECT 'c', 3 FROM dual
)
SELECT *
FROM (SELECT *
FROM dat
PIVOT (MAX(VALUE) FOR NAME IN ('a','b'))); -- list of the ones you need

query to select columns from a row in which another column has certain value only SQL

Consider the following table
id attribute
1 a
1 a
1 b
2 a
2 a
3 c
4 a
I want to select the ids that have attribute of 'a' only, ie 2 and 4.
Cant select 1 because 1 has 'a' and 'b', cant select 3 because it has 'c' only. We select 2 and 4 because it has 'a' value only.
You can use
SELECT id
FROM YourTable
GROUP BY id
HAVING MAX(attribute) = 'a' AND MIN(attribute) = 'a'
AND COUNT(*) = COUNT(attribute)
the
COUNT(*) = COUNT(attribute)
is to discard any id that have NULL attribute as well as a. Remove this if that is not the semantics you want or the column is not nullable anyway.
Please test this:
SELECT id
FROM attribute
GROUP BY id
HAVING
COUNT(DISTINCT attribute) = 1 AND MIN(attribute)= 'a';

SQL Counting the number of occurence based on a subject

I find it hard to word what I am trying to achieve. I have a table that looks like this:
user char
---------
a | x
a | y
a | z
b | x
b | x
b | y
c | y
c | y
c | z
How do I write a query that would return me the following result?
user x y z
-------
a |1|1|1|
b |2|1|0|
c |0|2|1|
the numbers represent the no of occurences of chars in the original table
EDIT:
The chars values are unknown hence the solution cannot be restricted to these values. Sorry for not mentioning it sooner. I am using Oracle DB but planning to use JPQL to construct the query.
select user,
sum(case when char='x' then 1 else 0 end) as x,
sum(case when char='y' then 1 else 0 end) as y,
sum(case when char='z' then 1 else 0 end) as z
from thetable
group by user
Or, if you don't mind stacking vertically, this solution will give you a solution that works even with unknown sets of characters:
select user, char, count(*) as count
from thetable
group by user, char
This will give you:
user char count
a x 1
a y 1
a z 1
b x 2
If you want to string an unknown set of values out horizontally (as in your demo output), you're going to need to get into dynamic queries... the SQL standard is not designed to generate output with an unknown number of columns... Hope this is helpful!
Another option, using T-SQL PIVOT (SQL SERVER 2005+)
select *
from userchar as t
pivot
(
count([char]) for [char] in ([x],[y],[z])
) as p
Result:
user x y z
----------- ----------- ----------- -----------
a 1 1 1
b 2 1 0
c 0 2 1
(3 row(s) affected)
Edit ORACLE:
You can build a similar PIVOT table using ORACLE.
The tricky part is that you need the right column names in the IN ([x],[y],[z],...) statement. It shouldn't be too hard to construct the SQL query in code, getting a (SELECT DISTINCT [char] from table) and appending it to your base query.
Pivoting rows into columns dynamically in Oracle
If you don't know the exact values on which to PIVOT, you'll either need to do something procedural or mess with dynamic sql (inside an anonymous block), or use XML (in 11g).
If you want the XML approach, it would be something like:
with x as (
select 'a' as usr, 'x' as val from dual
union all
select 'a' as usr, 'y' as val from dual
union all
select 'b' as usr, 'x' as val from dual
union all
select 'b' as usr, 'x' as val from dual
union all
select 'c' as usr, 'z' as val from dual
)
select * from x
pivot XML (count(val) as val_cnt for val in (ANY))
;
Output:
USR VAL_XML
a <PivotSet><item><column name = "VAL">x</column><column name = "VAL_CNT">1</column></item><item><column name = "VAL">y</column><column name = "VAL_CNT">1</column></item></PivotSet>
b <PivotSet><item><column name = "VAL">x</column><column name = "VAL_CNT">2</column></item></PivotSet>
c <PivotSet><item><column name = "VAL">z</column><column name = "VAL_CNT">1</column></item></PivotSet>
Hope that helps

Return different rows for each column in a row

I have data which is presented in multiple rows and columns with 0 or 1 values. What I'm trying to do is create a unique row for each 1, but there are sometimes multiple 1's in a row. For ex:
**A B C D**
1 0 1 1
0 0 0 1
1 1 0 0
I would like to have return six rows, all in one column like so
**RETURN**
A
C
D
D
A
B
Thanks in advance!
You can do this with a union all statement:
select val
from ((select 'A' as val from t where A = 1) union all
(select 'B' from t where B = 1) union all
(select 'C' from t where C = 1) union all
(select 'D' from t where D = 1)
) t
As a note: I hope you have other columns that you can include in the output. SQL tables are, by definition, not ordered. So, you really have no idea in your example of the original source for any given value.