Concatenate SQL table rows with conditions in single text - sql

I have a SQL table like this
col1 col2 col3
1 0 1
1 1 1
0 1 1
1 0 0
0 0 0
I am expecting output as like this
col1 col2 col3 NewCol
1 0 1 SL,PL
1 1 1 SL,EL,PL
0 1 1 EL,PL
1 0 0 SL
0 0 0 NULL
The condition for this is if col1>0 then SL else ' ', if col2>0 EL else ' ', if col3>0 PL else ' '
I tried to use Concatenate many rows into a single text string? but didn't able to achieve the desired result properly
I have tried It is working fine with a message
Invalid length parameter passed to the LEFT or SUBSTRING function.
WITH CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN 'SL,' ELSE '' END +
CASE WHEN col2 > 0 THEN 'EL,' ELSE '' END +
CASE WHEN col3 > 0 THEN 'PL,' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1, col2, col3,
substring(NewCol, 1, len(NewCol) - 1) AS NewCol
FROM CTE
But again my last condition is not matching if all columns is 0 then I have to show NULL as per desired output.
Find the attach fiddle http://sqlfiddle.com/#!6/2bd6a/1

The issue with your code example is that when all columns are 0 then the length is 0 and the substring function will throw an error.
Use nullif to fix it: substring(NewCol, 1, len(nullif(NewCol,'')) - 1) AS NewCol

You could also change to appending the delimiter on the front and use STUFF.
STUFF('',1,1,'') will return NULL rather than an error.
WITH
Employee(col1, col2, col3) AS (
SELECT 1,1,1 UNION ALL
SELECT 0,0,0
),
CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN ',SL' ELSE '' END +
CASE WHEN col2 > 0 THEN ',EL' ELSE '' END +
CASE WHEN col3 > 0 THEN ',PL' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1,
col2,
col3,
STUFF(NewCol, 1, 1, '')
FROM CTE
Returns
+------+------+------+------------------+
| col1 | col2 | col3 | (No column name) |
+------+------+------+------------------+
| 1 | 1 | 1 | SL,EL,PL |
| 0 | 0 | 0 | NULL |
+------+------+------+------------------+

You have to check with NULLIF to do this trick
Two ways
SELECT col1, col2, col3,
nullif(CASE WHEN col1 = 1 THEN 'SL,' ELSE '' END +
CASE WHEN col2 = 1 THEN 'EL,' ELSE '' END +
CASE WHEN col3 = 1 THEN 'PL,' ELSE '' END,'') AS NewCol
FROM Employee
OR
SELECT
col1,
col2,
col3,
substring(nullif(NewCol,''), 1, len(NewCol) - 1) AS NewCol
FROM
CTE

Related

Sum and count of records

I have a table with some records:
Col1
Col2
Col3
Col4
1
Row1
99
152
1
Row2
99
20
5
Row3
98
34
1
Row4
120
18
7
Row5
27
74
I need to get the sum of Col4 values where Col1 = 1, sum of Col4 values where Col3 = 99 and Col1 = 1, sum of Col4 values where Col3 <> 99 and Col1 = 1, total count of records where Col1 = 1, count of records where Col3 = 99 and Col1 = 1, count of records where Col3 <> 99 and Col1 = 1 (there is a possibility that there will be no records that meet the criteria).
My SQLite statement looks like that:
query.SQL.Text:= 'SELECT IFNULL(sum(Col4), 0), '+
'IFNULL(sum(case when Col3 = 99 then Col4 else 0 end), 0), ' +
'IFNULL(sum(case when Col3 <> 99 then Col4 else 0 end), 0), ' +
'IFNULL(count(*), 0), ' +
'IFNULL(sum(case Col3 = 99 then 1 else 0 end), 0), ' +
'IFNULL(sum(case Col3 <> 99 then 1 else 0 end), 0) ' +
'FROM myTable WHERE Col1 = :_Col1';
Is there a way to simplify it?
SQLite evaluates boolean expressions to 1 (true) or 0 (false), so a CASE expression like:
case when Col3 = 99 then 1 else 0 end
can be simplified to:
Col3 = 99
Also, the ELSE part in a CASE expression like:
CASE WHEN Col3 = 99 THEN Col4 ELSE 0 END
is not needed because later you use IFNULL() to return 0 in case it returns NULL.
Finally, COUNT(*) never returns NULL, so IFNULL() is not needed in this case.
Simplify your code to this:
SELECT IFNULL(SUM(Col4), 0),
IFNULL(SUM(CASE WHEN Col3 = 99 THEN Col4 END), 0),
IFNULL(SUM(CASE WHEN Col3 <> 99 THEN Col4 END), 0),
COUNT(*),
IFNULL(SUM(Col3 = 99), 0),
IFNULL(SUM(Col3 <> 99), 0)
FROM myTable
WHERE Col1 = 1;
See the demo.

Count occurance in a row in SQLite just by SQL?

I have a DB contain 5 columns, all are integers range from 1~5 e.g.
1,1,2,3,1
5,1,2,3,4
4,2,3,2,1
....
is there a way to count number of occurrence of, say 1 in first row by just SQL ? (in this case, 3 should be return). select count() just deal with number of records return in column manner. Thanks.
Regds
LAM Chi-fung
You can combine case with count to get five columns, each with the count of the values 1 - 5:
select
case when col1 = 1 then 1 else 0 end + case when col2 = 1 then 1 else 0 end + case when col3 = 1 then 1 else 0 end + case when col4 = 1 then 1 else 0 end + case when col5 = 1 then 1 else 0 end as count_1
,case when col1 = 2 then 1 else 0 end + case when col2 = 2 then 1 else 0 end + case when col3 = 2 then 1 else 0 end + case when col4 = 2 then 1 else 0 end + case when col5 = 2 then 1 else 0 end as count_2
,case when col1 = 3 then 1 else 0 end + case when col2 = 3 then 1 else 0 end + case when col3 = 3 then 1 else 0 end + case when col4 = 3 then 1 else 0 end + case when col5 = 3 then 1 else 0 end as count_3
,case when col1 = 4 then 1 else 0 end + case when col2 = 4 then 1 else 0 end + case when col3 = 4 then 1 else 0 end + case when col4 = 4 then 1 else 0 end + case when col5 = 4 then 1 else 0 end as count_4
,case when col1 = 5 then 1 else 0 end + case when col2 = 5 then 1 else 0 end + case when col3 = 5 then 1 else 0 end + case when col4 = 5 then 1 else 0 end + case when col5 = 5 then 1 else 0 end as count_5
from table_x
You can use:
select t.*,
(col1 = 1) + (col2 = 1) + (col3 = 1) + (col4 = 1) + (col5 = 1) as num_1s
from t
SQLite treats boolean expressions like numbers in an arithmetic context, with 1 for true and 0 for false. You can also express this more verbosely as:
select t.*,
(case when col1 = 1 then 1 else 0 end +
case when col2 = 1 then 1 else 0 end +
case when col3 = 1 then 1 else 0 end +
case when col4 = 1 then 1 else 0 end +
case when col5 = 1 then 1 else 0 end +
) as num_1s
from t;
By unpivoting the data, you can get the count for all values in all columns in a single query, without the need to know the possible values in advance
sqlite> select * from t;
col1 col2 col3 col4 col5
---------- ---------- ---------- ---------- ----------
1 1 2 3 1
5 1 2 3 4
4 2 3 2 1
sqlite> select col
...> ,count(*) as cnt
...> from ( select col1 as col from t
...> union all select col2 from t
...> union all select col3 from t
...> union all select col4 from t
...> union all select col5 from t
...> )
...> group by col
...> ;
col cnt
---------- ----------
1 5
2 4
3 3
4 2
5 1
sqlite>

Two select statement with case

I have two queries and I have a value if value is 1 then first query will execute if value is 2 then second. How can i achieve this, my query is
Query one if value is 1
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END )AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS VARCHAR(10)) + ' / 1' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS "matches" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END )
)
Query 2 if value 2
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END
)AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END
+ CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS VARCHAR(10)) + '/ 2' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS "NUM_OF_MATCHES" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END+
CASE WHEN col2 = 10 THEN 1 ELSE 0 END )
I have try it using case but it is not working
I want if value = 1 then first query will run and if value = 2 then second
although both queries doing same work but if value is 1 then col1 logic will take only col1 and if value is 2 then it will take col1 and col2 if value is 3 then it will take col1 col2 and col3 till 6 col
You can make use of a simple if else if and execute both the queries.
IF(#value=1)
BEGIN
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END )AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS VARCHAR(10)) + ' / 1' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS "matches" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END )
)
END
ELSE IF(#value=2)
BEGIN
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END
)AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END
+ CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS VARCHAR(10)) + '/ 2' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS "NUM_OF_MATCHES" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END+
CASE WHEN col2 = 10 THEN 1 ELSE 0 END )
END
still are you using CASE Statement, why dont you try to use IIF Statement, IIF Statement is more efficient and fast compare to CASE Statement.
e.g.
select IIF(1=1, (your desired column1),(your desired column2)) as matches
you can also use nested IIF Statement in single query like CASE Statement..
select IIF(1=1, (IIF(2=2, (your desired column1),(your desired column2))),(your desired column3)) as matches.

SQL Server Sum rows with string value

I have a dynamic SQL query which returns rows like below with string values & numeric values.
EMP col1 col2 col3 col4 col5
----------------------------
A1 4 4 3 3 3
A2 4 2 5 3 3
A3 sd 3 3 1 sd
A4 3 4 3 3 3
Now I need a new column which sums col1 to col5 and creates a total sum column where it should ignore the string values as in row 3. There are no NULL values
How could I achieve this? Using ISNUMERIC might be the solution, but I'm not sure how to use it in such a scenario.
You can use a CASE Expression to determine whether the value is a number. If it is a number then either cast the value to an INT or DECIMAL data type, otherwise use 0 so it doesn't effect the sum.
SELECT
CASE WHEN ISNUMERIC(col1) = 1 THEN CAST(col1 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col2) = 1 THEN CAST(col2 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col3) = 1 THEN CAST(col3 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col4) = 1 THEN CAST(col4 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col5) = 1 THEN CAST(col5 as INT) ELSE 0 END as SumValue
FROM MyTable
If you're on SQL Server 2012, TRY_CONVERT avoids pitfalls commonly encountered with ISNUMERIC:
SELECT col1, col2, col3, col4, col5,
ISNULL(TRY_CONVERT(int, col1), 0) +
ISNULL(TRY_CONVERT(int, col2), 0) +
ISNULL(TRY_CONVERT(int, col3), 0) +
ISNULL(TRY_CONVERT(int, col4), 0) +
ISNULL(TRY_CONVERT(int, col5), 0) AS total
FROM Employee
SQLFiddle
You can do this with a big case statement:
select q.*,
((case when isnumeric(col1) = 1 then cast(col1 as int) else 0 end) +
(case when isnumeric(col2) = 1 then cast(col2 as int) else 0 end) +
(case when isnumeric(col3) = 1 then cast(col3 as int) else 0 end) +
(case when isnumeric(col4) = 1 then cast(col4 as int) else 0 end) +
(case when isnumeric(col5) = 1 then cast(col5 as int) else 0 end)
) as newcol
from q;
isnumeric() should be sufficient for your purposes. You might need fancier logic if you only want positive integers or want to exclude exponential notations or the like.
You're on the right track with isnumeric:
select
emp,
(case when isnumeric(col1) = 1 then cast(col1 as int) else 0 end) +
col2...
from table1

SQL query about self join

I have a sql in db2 as below:
SELECT distinct KEY_COL, MY_TYPE1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL1 ELSE '' END AS NEWCOL1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL2 ELSE '' END AS NEWCOL2,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL1 ELSE '' END AS NEWCOL3,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL2 ELSE '' END AS NEWCOL4
FROM MYSCHEMA.MYTABLE
As clear from above query, based on MY_TYPE2 colums in MYSCHEMA.MYTABLE, the new column values are decided.
If the MY_TYPE2 is one, col1 and col2 goes to newcol1 and newcol2 respectively for given key and MY_TYPE1 column. But if the MY_TYPE2 is two for same key and MY_TYPE1, then col1 and col2 goes to newcol3 and newcol4.
The output table looks something like below:
KEY_COL | MY_TYPE1 | NEWCOL1 | NEWCOL2 | NEWCOL3 | NEWCOL4
=========================================================
1 T1 1 2
1 T1 4 3
1 T2 2 3
1 T2 4 1
========================================================
However, I want a single row based on MY_TYPE1 column as below:
KEY_COL | MY_TYPE1 | NEWCOL1 | NEWCOL2 | NEWCOL3 | NEWCOL4
=========================================================
1 T1 1 2 4 3
1 T2 2 3 4 1
========================================================
How to modify the query to achieve above result ?
Thanks for reading!
select key_col, my_type1, max(newcol1), max(newcol2), max(newcol3), max(newcol4)
from
(
SELECT distinct KEY_COL, MY_TYPE1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL1 ELSE '' END AS NEWCOL1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL2 ELSE '' END AS NEWCOL2,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL1 ELSE '' END AS NEWCOL3,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL2 ELSE '' END AS NEWCOL4
FROM MYSCHEMA.MYTABLE
) definedTable
group by key_col, my_type1
select KEY_COL ,max(MY_TYPE1),max(NEWCOL1),max(NEWCOL2),max(NEWCOL3),max(NEWCOL4)
from table
group by KEY_COL