How can I acces the output from the first select statement - sql

I have a table Like this
Col1 | Col2
-----------
a | d
b | e
c | a
Now I want to create an statement to get an output like this:
First| Second
-------------------
a | Amsterdamm
b | Berlin
c | Canada
...
So far I have this consturct what is not working
SELECT *
FROM(
SELECT DISTINCT
CASE
when Col1 IS NULL then 'NA'
else Col1
END
FROM Table1
UNION
SELECT DISTINCT
CASE
when Col2 IS NULL then 'NA'
else Col2
END
FROM Table1
) AS First
,
(
SELECT DISTINCT
when First= 'a' then 'Amsterdam'
when First= 'b' then 'Berlin'
when First= 'c' then 'Canada'
) AS Second
;
can you help me with that
Sorry I have to edit my question to be more specific.

Not as familiar with DB2... I'll lookup if it has a concat function in a sec... and it does.
SELECT First, case when first = 'a' then
concat('This is a ',first)
case when first = 'b' then
concat('To Be or not to ',first)
case else
concat('This is a ',first) end as Second
FROM (
SELECT coalesce(col1, 'NA') as First
FROM Table
UNION
SELECT coalesce(col2, 'NA')
FROM table) SRC
WHERE first <> 'NA'
What this does is generate a single inline view called src with a column called first. If col1 or col2 of table are null then it substitutes NA for that value. It then concatenates first and the desired text excluding records with a first value of 'NA'
Or if you just create an inline table with the desired values and join in...
SELECT First, x.b as Second
FROM (
SELECT coalesce(col1, 'NA') as First
FROM Table
UNION
SELECT coalesce(col2, 'NA')
FROM table) SRC
INNER JOIN (select a,b
from (values ('a', 'This is a'),
('b', 'To B or not to' ),
('c', 'I like cat whose name starts with')) as x(a,b)) X;
on X.a = src.first
WHERE first <> 'NA'
Personally I find the 2nd option easier to read. Though if you have meaning for a,b,c I would think you'd want that stored in a table somewhere for additional access. In code seems like a bad place to store data like this that could change.
Assuming you want
a this is a a
b this is a b
c this is a c
d this is a d
e this is a e

thanks to xQbert
I could solve this problem like this
SELECT FirstRow, concat
(
CASE FirstRow
WHEN 'AN' then 'amerstdam'
WHEN 'G' then 'berlin'
ELSE 'NA'
END, ''
) AS SecondRow
FROM(
Select coalesce (Col1, 'NA') as FirstRow
FROM Table1
UNION
Select coalesce (Col2, 'NA')
FROM Table1) SRC
WHERE FirstRow <> 'NA'
;

Related

SQL Server Weird Grouping Scenario by multiple columns and OR

I have a weird grouping scenario and have some troubles finding out what would be the best way for grouping in SQL.
Imagine we have the following one table
CREATE TABLE Item
(
KeyId VARCHAR(1) NOT NULL,
Col1 INT NULL,
Col2 INT NULL,
Col3 INT NULL
)
GO
INSERT INTO Item (KeyId, Col1, Col2, Col3)
VALUES
('a',1,2,3),
('b',5,4,3),
('c',5,7,6),
('d',8,7,9),
('e',11,10,9),
('f',11,12,13),
('g',20,22,21),
('h',23,22,24)
I need to group records in this table so that if Col1 OR Col2 OR Col3 is the same for two records, then these two records should be in the same group, and there should be chaining.
In other words, with the data as above record 'a' (first record) has Col3 = 3 and record 'b' (second record) has also Col3 = 3, so these two should be in one group. But then record 'b' has the same Col1 as record 'c', so record 'c' should be in the same group as 'a' and 'b'. And then record 'd' has the same Col2 as in 'c', so this should also be in the same group. Similarly 'e' and 'f' has the same values in Col3 and Col1 respectively.
On the other hand records 'g' and 'h' will be in one group (because they have the same Col2 = 22), but this group will be different from the group for records 'a','b','c','d','e','f'.
The result of the query should be something like
KeyId GroupId
'a' 1
'b' 1
'c' 1
'd' 1
'e' 1
'f' 1
'g' 2
'h' 2
There is probably a way of doing this with some loops/cursors, but I started thinking about cleaner way and this seems quite difficult.
Here you go:
with g (rootid, previd, level, keyid, col1, col2, col3) as (
select keyid, '-', 1, keyid, col1, col2, col3 from item
union all
select g.rootid, g.keyid, g.level + 1, i.keyid, i.col1, i.col2, i.col3
from g
join item i on i.col1 = g.col1 or i.col2 = g.col2 or i.col3 = g.col3
where i.keyid > g.keyid
),
m (keyid, rootid) as (
select keyid, min(rootid) from g group by keyid
)
select * from m;
Result:
keyid rootid
----- ------
a a
b a
c a
d a
e a
f a
g g
h g
Note: Keep in mind that SQL Server has by default a limit of 100 iterations (number of rows per group) when processing recursive CTEs. In English: even though it's possible to do this as shown above, there are clear limitations to what SQL Server can process. If you reach this limit you'll get the message:
The maximum recursion 100 has been exhausted before statement completion.
If this happens consider adding the clause option (maxrecursion 32767).

How do I find all values where all rows associated with that value meet a condition?

I have a table in SQL that is structured as follows:
Name Value1 Value2
A .2 .3
A .1 .05
A .5 .3
B .2 .4
B .1 .08
C .3 .4
C .2 .5
C .1 .3
How do I get all the Names where Value1 is less than Value2 for every row associated with a Name? In the example above, I would only want to pull out Name C.
I read this article: Select in MySQL where all rows meet a condition
but I don't think this applies to my problem, as this solution assumes you are comparing a row to fixed value.
A variant on some of the other answers, also using conditional aggregation:
SELECT Name
FROM yourTable
GROUP BY Name
HAVING SUM(CASE WHEN value1 >= value2 THEN 1 ELSE 0 END) = 0;
The above query asserts that each matching name group does not have any record for which value1 is greater than or equal to value2.
You can use group by and having:
select name
from t
group by name
having count(*) = sum(case when value1 < value2 then 1 else 0 end);
There are other ways to phrase this, such as:
select distinct name
from t
where not exists (select 1 from t t2 where t2.name = t.name and t2.value2 >= t2.value1);
Or:
select name
from t
except
select name
from t
where value2 >= value1;
You can get desired result with in clause
declare #table table (name varchar(10), value1 float, value2 float)
insert #table
select 'A', '0.2', '.3'
union all
select 'A' , '.1', '.05'
union all
select 'A', '.5', '.3'
union all
select 'B', '.2', '.4'
union all
select 'B', '.1' , '.08'
union all
select 'C', '.3' , '.4'
union all
select 'C', '.2' , '.5'
union all
select 'C' , '.1' , '.3'
Use In Clause where value1<value2
select * from #table where value1<value2
and name not in ( select name from #table where value1>value2)
You can use EXIST to check if the value exist in your desired condition wherein all rows by certain name have value2 greater than value1.
SELECT *
FROM TableName a
WHERE EXISTS (SELECT 1
FROM TableName b
WHERE a.name = b.Name
GROUP BY b.name
HAVING COUNT(case when b.value1 < b.value2 THEN 1 END) = COUNT(*))
Here's a Demo.
This will display all rows for the valid name. However, check other answer if you only want to display distinct name.

How to find count of multiple columns in sql group by id?

I have a table with schema like below:
root
|id
|name
|col1
|col2
|...
|col30
Conditions are that multiple rows can have the same name (they're not primary key - the key is the ID). Values in col1-col30 will be some string, or it can have the string "null".
I'm interested in the number of columns filled in for each name.
For example,
if name "test1" has col1-5 filled in a row, and another row has "test1" and have col1, 3, 10, 6 filled in (and the rest of unfilled columns are just string value "null"), "test1" should have value 9.
I'm pretty new to SQL and have been looking this up.. Please help.
Give this a try:
SELECT
name,
CASE WHEN col1_max IS NOT NULL THEN 1 ELSE 0 END + -- Only include non-NULL values
CASE WHEN col2_max IS NOT NULL THEN 1 ELSE 0 END
FROM (
SELECT
name,
MAX(col1) AS col1_max, -- Non-NULL values come before NULL
MAX(col2) AS col2_max
FROM MyTable
GROUP BY name
) src
You can add more the rest of the columns to fit your case.
Updated
I just realized your NULL case is with a "null" string. Modified:
SELECT
name,
CASE WHEN col1_max IS NOT NULL THEN 1 ELSE 0 END + -- Only include non-NULL values
CASE WHEN col2_max IS NOT NULL THEN 1 ELSE 0 END
FROM (
SELECT
name,
MAX(CASE WHEN col1 = 'null' THEN NULL ELSE col1 END) AS col1_max, -- Non-NULL values come before NULL
MAX(CASE WHEN col2 = 'null' THEN NULL ELSE col2 END) AS col2_max
FROM MyTable
GROUP BY name
) src
First you unpivot your table and count those rows that have not null values. In postgres, you can achieve this with unnest. I have only used col1..7 -- change to upto col30 in your case
WITH t AS(
SELECT id,name,
unnest(array['col1', 'col2', 'col3', 'col4', 'col5', 'col6', 'col7']) AS colname,
unnest(array[col1, col2, col3, col4, col5, col6, col7]) AS colvalue
FROM your_table)
SELECT id, name,
SUM(CASE WHEN colvalue IS NULL THEN 0 ELSE 1 END) AS count_filled
FROM t
GROUP BY 1,2;

Search SQL and return true or false

I have a table that has thousands of rows in. I need to check if certain values exists in the table or not.
I want to list all the bar codes I am searching with a flag of true or false returned if there is one.
I have come up with this so far:
SELECT CASE WHEN EXISTS (
SELECT *
FROM TABLE
WHERE Coulmn in ('a','b', 'c', 'd', 'e', 'f', 'g')
)
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT) END
This however just returns a value of 1.
So in the table I have
coulmn
----------
A
B
D
E
F
G
I want to do a search that returns the following
Coulmn | Exsists
-----------------
A | True
B | True
C | False
D | True
E | True
F | True
G | True
You can use a query like the following:
SELECT t1.v,
CASE WHEN t2.col IS NOT NULL THEN 'true' ELSE 'false' END AS Exists
FROM (
SELECT 'a' AS v UNION ALL SELECT 'b' UNION ALL SELECT 'c' UNION ALL SELECT 'd'
UNION ALL SELECT 'e' UNION ALL SELECT 'f' UNION ALL SELECT 'g') AS t1
LEFT JOIN mytable AS t2 ON t1.v = t2.col
This works:
SELECT *, CASE WHEN (Column in ('1','2')) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END AS result_field
FROM TABLE;
NOTE: Tested in PostgreSQL
As it's written, the outer select is select case when exists () then 1 else 0 end... so it is only going to return one row. The outer select must include "Column" AND "Exists" (select column, ...) to return two columns.
A "where" clause will never return a "false" like this, though, because "column" has to be in a real table for the query to actually return it. As #jarlh says, you'll need a helper table to store the columns you're looking for:
Create table SearchColumns (SearchColumn char(1));
insert into SearchColumns (SearchColumn)
values ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H')
Then you can do the If Exists to your table from that table to see which values are in or not in:
select SearchColumn, case when exists
(select * from TABLE where Table.Column = SearchColumns.SearchColumn)
then 'True' else 'False' end as ExistsStatus
from SearchColumns
I think that will get you what you want. This gets a) Only one record per column no matter how many times it occurs in your table and b) "True" and "False" for every column value you're looking for. If you really wanted a Bit, you can use 0 and 1 and the casting from the original query, but they actually show "0" and "1"; and c) this should work no matter how many values you have.
(Note, I assumed some of those were spelling errors, so I made adjustments, but they were consistent so I'm not certain).
With the help form above I created a temp table and then implemented one of the soultions shared.
CREATE TABLE #Temp
(
Barcode VARCHAR (100)
)
INSERT INTO #Temp
VALUES
(1),
(2),
(3),
(4 )
select barcode, case when exists
(select * from CIPKORHHTProductDetails where CIPKORHHTProductDetails.Barcode = #temp.barcode)
then 'True' else 'False' end as ExistsStatus
from #temp order by ExistsStatus DESC

How to write query to return value regardless of existance?

Given this:
with data_row as (select 1 as col_1 from dual)
select 'Y' as row_exists from dual where exists
(select null
from data_row
where col_1 in (2,1))
How can I get this?
Col_1 Row_exists
--------------------
1 Y
2 N
In order to get a row of output, you need a row of input. You want to get the second row with a "2", but there is no table with that value.
The approach is to generate a table that has the values that you want, and then use left outer join to find which match:
with data_row as (
select 1 as col_1
from dual
),
what_i_care_about as (
select 1 as col from dual union all
select 2 from dual
)
select wica.col,
(case when dr.col_1 is NULL then 'N' else 'Y' end) as row_exists
from what_i_care_about wica left outer join
data_row dr
on wica.col = dr.col_1;
You cannot do directly what you want -- which is to create a row for each missing value in the in list. If you have a lot of values and they are consecutive numeric, then you can use connect by or a recursive CTE to generate the values.