How to hardcore values in Select statement in DB2 - sql

I was wondering if there is a way we could put a few string values on the select statement to create variables to be used later.
E.g.
SELECT 'A','B" AS AB FROM TEMP_TABLE
RESULT
AB
A
B

You can use sysibm.sysdummy1:
select 'A' as AB from sysibm.sysdumm1 union all
select 'B' as AB from sysibm.sysdumm1

Db2 has global variables which you could consider.
Otherwise, you can use a VALUES statement. E.g.
SELECT * FROM TABLE(VALUES ('A', 1,2),('B', 1,3)) AS VARS(AB,I,J)
which returns
AB|I|J
--|-|-
A |1|2
B |1|3

Related

Count for a list of items with zero for does not exist

If I have a table t1 with:
my_col
------
foo
foo
bar
And I have a list with foo and hello
How can I get:
my_col | count
-------|-------
foo | 2
hello | 0
If I just do
SELECT my_col, COUNT(*)
FROM t1
WHERE my_col in ('foo', 'hello')
GROUP BY my_col
I get
my_col | count
-------|------
foo | 2
without any value for hello.
I'm specifically wanting this to be in reference to a list of items because this will be called in a program where the list is a variable.
Ideally you should maintain a separate table with all the possible column values which you want to appear in your report. In the absence of that, we can try using a CTE here:
WITH cte AS (
SELECT 'foo' AS my_col UNION ALL
SELECT 'bar' UNION ALL
SELECT 'hello'
)
SELECT
a.my_col,
COUNT(b.my_col) AS count
FROM cte a
LEFT JOIN t1 b
ON a.my_col = b.my_col
WHERE
a.my_col IN ('foo', 'hello')
GROUP BY
a.my_col;
Demo
Here's yet another way, using values:
select
t2.my_col, count (t1.my_col)
from
(values ('foo'), ('hello')) as t2 (my_col)
left join t1 on t1.my_col = t2.my_col
group by
t2.my_col
Note that count (t1.my_col) returns a 0 for "hello" since nulls are not counted. count (*) by contast would have returned 1 for "hello" because it was counting the row.
You can turn your list into a set of rows and use a LEFT JOIN, like :
SELECT x.val, COUNT(t.my_col)
FROM
(SELECT 'foo' val UNION SELECT 'hello') x
LEFT JOIN t ON t.my_col = x.val
GROUP BY x.val
Postgres solution:
One way is to place the 'list' into an ARRAY, and then convert the ARRAY into a column using unnest. Then perform a left join on that column with the other table and perform a count.
WITH t1 AS (
SELECT 'foo' AS my_col UNION ALL
SELECT 'foo' UNION ALL
SELECT 'bar'
)
SELECT
a.my_col,
COUNT(b.my_col) AS count
FROM unnest(ARRAY['foo', 'hello']) a (my_col)
LEFT JOIN t1 b
ON a.my_col = b.my_col
GROUP BY
a.my_col;
The issue I had with the other answers is that (while they they helped me get to the solution) they did not provide a solution where the items of interest were in a single list (which isn't an actual sql term, so the fault is on me).
However, my real use case is to perform a native query using java and hibernate, and unfortunately the above does not work because the typing cannot be determined. Instead I converted my list into a single string and used string_to_array in place of the ARRAY function.
So the solution that worked best for my use case is below (but at this point, the other answers would be just as correct since I'm now having to do manual string manipulation, but I'm leaving this here for the sake of posterity)
WITH t1 AS (
SELECT 'foo' AS my_col UNION ALL
SELECT 'foo' UNION ALL
SELECT 'bar'
)
SELECT
a.my_col,
COUNT(b.my_col) AS count
FROM unnest(string_to_array('foo, hello', ',')) a (my_col)
LEFT JOIN t1 b
ON a.my_col = b.my_col
GROUP BY
a.my_col;

Behavior of VALUES clause in PostgreSQL

In Postgres, according to its doc, the following works:
select 1 as column1, 'one' as column2
union all
select 2, 'two'
union all
select 3, 'three'
however its extension:
select * from (select 1 as column1, 'one' as column2
union all
select 2, 'two'
union all
select 3, 'three')
results in error:
Similarly, while this works (assuming Postgres creates internal alias?):
values(1,'a'), (2, 'b')
the following results in error, requiring an alias:
select * from (values(1,'a'), (2, 'b'))
and only starts working when such alias is provided:
select * from (values(1,'a'), (2, 'b')) t(z,y)
Same inconsistency seems to also apply to SELECT clause, i.e.:
select 1, 2
works independently but not as a subselect:
select * from (select 1, 2)
unless provided with an alias:
select * from (select 1, 2) t(a, b)
Would it not be a logical extension of the behavior of clauses dealing with sets (SELECT, VALUES, etc.) to assume some internal alias when used inside another select like Postgres already does when use those clauses independently?
What was the reasoning that lead to such inconsistency in design?
The syntax for using VALUES with select is certainly different than how it used in most flavors of SQL with insert. That being said, the issue here with Postgres actually seems to be that the VALUES clause needs to be wrapped in parentheses as a subquery in order for it to be eligible for use with select (it won't work otherwise). Therefore, we can think of the following as being equivalent to any other subquery:
select *
from
(
values (1,'a'), (2, 'b')
) t;
If the VALUES clause were replaced with a select, we would have to alias the subquery, and the same holds true with VALUES. As to why Postgres chose to do this, you might have to check the documentation or ask a question on their forum.

sql if statement in function

I have a fuction in visual basic and I'm sending a and b variables into the fuction. It does a lot of select statements as seen below:
SQL CODE
Select xxx where a=#a
union
Select yyy where u=#a
I want to add one more union with if statement.
I want to run one part if #b=1 and other part if #b=2
union
if #b=1
select zzz
if #b=2
select ttt
I want to learn how to use union with if statement and correct syntax of it.
union
if #b=1
begin
select zzz
end
else if( #b=2)
select ttt
end
is it correct?
Thanks.
I think you can put your checks in the WHERE clause. If they fail now rows are selected and therefore no rows are added to the overall result.
...
UNION
SELECT ...
WHERE #b = 1
UNION
SELECT ...
WHERE #b = 2;

How to define temporary table values in a subquery in Oracle

I am approaching this issue from a non DBA perspective, as in I do not have permissions to create new tables for the database. I am trying to work around this by using a subquery in Oracle kind of like this sudo code:
With temptable as ('col1name', 'col2name', 1,'a',2,'b')
Select * from temptable where col1name = 1
With the temptable looking like
Col1name | Col2name
1 a
2 b
And the output being row 1. I know it is not the easiest way to do it, but it is all I can think of to accomplish my task until I can get the admin to approve a new table. I have searched a lot but I can't find an answer. Is there a simple way to define temporary table data like this?
I would just do this as:
with temptable as (
select 1 as col1name, 'a' col2name from dual union all
select 2, 'b' from dual
)
Select *
from temptable
where col1name = 1;
As an alternative to a CTE (common table expresssion) as suggested by Gordon, you can also use a query as an old-school inline view.
For example:
SELECT tt.col1name
, tt.col2name
FROM ( SELECT 1 AS col1name, 'a' AS col2name FROM DUAL
UNION ALL SELECT 2, 'b' FROM DUAL
UNION ALL SELECT 3, 'c' FROM DUAL
) tt
WHERE tt.col1name = 1
ORDER
BY tt.col1name

Double IN Statements in SQL

Just curious about the IN statement in SQL.
I know I can search multiple columns with one value by doing
'val1' IN (col1,col2)
And can search a column for multiple values
col1 IN ('val1','val2')
But is there a way to do both of these simultaneously, without restorting to an repeating AND / OR in the SQl? I am looking to do this in the most scalable way, so independent of how many vals / cols i need to search in.
So essentially:
('val1','val2') IN (col1,col2)
but valid.
You could do something like this (which I've also put on SQLFiddle):
-- Test data:
WITH t(col1, col2) AS (
SELECT 'val1', 'valX' UNION ALL
SELECT 'valY', 'valZ'
)
-- Solution:
SELECT *
FROM t
WHERE EXISTS (
SELECT 1
-- Join all columns with all values to see if any column matches any value
FROM (VALUES(t.col1),(t.col2)) t1(col)
JOIN (VALUES('val1'),('val2')) t2(val)
ON col = val
)
Of course, one could argue, which version is more concise.
Yes, for example you can do this in Oracle:
select x, y from (select 1 as x, 2 as y from dual)
where (x,y) in (select 1 as p, 2 as q from dual)