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
Related
Are there other special literal values besides NULL in SQL / PostgresQL?
NULL is nice in that we can interpret NULL as the concept of "nothing" (i.e. missing, not available, not asked, not answered, etc.), and data columns of any type can have NULL values.
I would like another value that I can interpret as representing another concept (here the idea of "everything"), in the same result set.
Is there another special value that I can return in a query, which like NULL doesn't type conflict?
Basically anything that doesn't throw ERROR: For 'UNION', types varchar and numeric are inconsistent in this toy query:
select 1 as numeral, 'one' as name UNION ALL
select 2 as numeral, 'two' as name UNION ALL
select NULL as numeral, NULL as name UNION ALL
select -999 as numeral, -999 as name UNION ALL -- type conflict
select '?' as numeral, 'x' as name -- type conflict
Here,
-999 doesn't work as its type conflicts with varchar columns
'~' doesn't work as its type conflicts with numeric columns
NULL doesn't work as it needs
More specifically here's my actual case, counting combinations of values and also include "Overall" rows in the same query. Generally I won't know or control the types of columns A, B, C in advance. And A, B, or C might also have NULL values which I would would still want to count separately.
SELECT A, COUNT(*) FROM table GROUP BY 1
UNION ALL
SELECT ?, COUNT(*) FROM table GROUP BY 1
and get a result set like:
A
COUNT
NULL
2
1
3
2
5
3
10
(all)
20
SELECT B, COUNT(*) FROM table GROUP BY 1
UNION ALL
SELECT ?, COUNT(*) FROM table GROUP BY 1
and get a result set like:
B
COUNT
NULL
2
'Circle'
3
'Line'
5
'Triangle'
10
(all)
20
You can use function CAST to convert the format to VARCHAR to be considered as string.
NOTE: Thanks to the comments above, I should completely rephrase this question as "How to COUNT/GROUP BY with ROLLUP using multiple columns of mixed/arbitrary/unknown types, and differentiate true NULL values from ROLLUP placeholders?"
The correct answer I believe is provided by #a_horse_with_no_name: use ROLLUP with GROUPING.
Below is is just me drafting that more completely with a revised example:
This toy example has an integer and a string
WITH table AS (
select 1 as numeral, 'one' as name UNION ALL
select 2 as numeral, 'two' as name UNION ALL
select 2 as numeral, 'two' as name UNION ALL
select NULL as numeral, NULL as name UNION ALL
select NULL as numeral, NULL as name UNION ALL
select NULL as numeral, NULL as name
)
select name, numeral, COUNT(*), GROUPING_ID()
FROM table
GROUP BY ROLLUP(1,2)
ORDER BY GROUPING_ID, name, numeral ;
It returns the following result:
numeral
name
count
grouping_id
note
NULL
NULL
3
0
both are true NULLs as grouping is 0
1
one
1
0
2
two
2
0
NULL
NULL
3
1
first is a true NULL, second is a ROLLUP
1
NULL
1
1
2
NULL
2
1
NULL
NULL
6
3
both NULLs are ROLLUPs
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';
I expect my query would give me the type list when at each columns give YES.
The table look this:
a b c d no
yes null yes null 1
null yes yes null 2
yes null null yess 3
the desired result from the query:
no type
1 a
1 c
2 b
2 c
3 a
3 d
how should I write my query in order to get my expected result?
thanks in advance.
Either look into pivot tables or union with multiple queries:
SELECT no,'a' AS type FROM t WHERE a IS NOT NULL
UNION SELECT no,'b' FROM t WHERE b IS NOT NULL
UNION SELECT no,'c' FROM t WHERE c IS NOT NULL
UNION SELECT no,'d' FROM t WHERE d IS NOT NULL
ORDER BY no,type
EDIT (see comments):
SELECT no,'a' AS type FROM t WHERE a = 'yes'
UNION SELECT no,'b' FROM t WHERE b = 'yes'
UNION SELECT no,'c' FROM t WHERE c = 'yes'
UNION SELECT no,'d' FROM t WHERE d = 'yes'
ORDER BY no,type;
Demo: db<>fiddle
As an alternative, you could use unnest:
WITH cte as
(SELECT no,
unnest(array['a', 'b', 'c', 'd']) as type,
unnest(array[a, b, c, d]) as colvalue
from abcdtypes)
SELECT no, type
FROM cte
where colvalue = 'yes'
ORDER BY 1, 2;
It works and is arguably more elegant. But I would only do something like this, if there were very many columns. For the four in your example, I too would side with Jim Jones.
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';
I'v a problem with look like the same as Union Select Only One Row
But with little different. I'v four selects combined with the union statment.
select top 1 value from (
select 1 as id, value from resource where rkey = 'a'
union
select 2 as id, value from resource where rkey = 'b'
union
select 3 as id, value from resource where rkey = 'c'
union
select 4 as id, value from resource where rkey = 'd'
) as x
order by id
Each of the select statement gives only one or zero rows back. I already would use the first result of all selects. So if the first select returns one row then the other selects should be ignored. And if the second select gives the row back (the first select gives no row back) then the others should be ignored. etc...
My question is: How fast is it in this combination or is there a faster solution?
Or skip the UNION:
select top 1 value
from resource
where rkey in ('a','b','c','d')
order by rkey
If key is indexed your approach (but using UNION ALL) might be the best.
Otherwise try:
select top 1 value
from resource
where rkey in ('a', 'b', 'c', 'd')
order by
case rkey
when 'a' then 1
when 'b' then 2
when 'c' then 3
when 'd' then 4
end