SQL Server : SUM of column with alphanumeric values - sql

I want to get the sum of a column that is alphanumeric. I want to add numeric values and return column values if not numeric. What I did is a added a CASE WHEN that looks like this
CASE
WHEN intAllocatedResourceperDivision NOT IN ('CL', 'HS', 'HV', 'ML', 'SL', 'VL', 'HC', 'S', '*')
THEN CAST(SUM(ISNULL(CAST(intAllocatedResourceperDivision AS DECIMAL), 0.00)) AS NVARCHAR(250))
ELSE intAllocatedResourceperDivision
END intAllocatedResourceperDivision
So I assume that all numeric values will be added and if values is in ('CL', 'HS', 'HV', 'ML', 'SL', 'VL', 'HC', 'S', '*') it will be returned as is.
But I'm getting
Error converting data type nvarchar to numeric.

Looks like your SUM aggregation is out of place. You only sum if the condition in the case statement is true. Try this:
SUM(case when intAllocatedResourceperDivision NOT IN ('CL','HS','HV','ML','SL','VL','HC','S','*') THEN intAllocatedResourceperDivision else 0 end)
In case you don't know the exact potential combination of non numeric values, you can use the ISNUMERIC function (assuming you're using SQL Server) to test whether or not the value is a number and assign a 0 if it's not, aggregating the final result.
SUM(case when ISNUMERIC(intAllocatedResourceperDivision) = 1 then intAllocatedResourceperDivision else 0 end)
To aggregate the numerical values and also keep non-numerical, you can use a union query as such:
select
cast(SUM(cast(intAllocatedResourceperDivision as decimal(18,2))) as varchar)
from
YOUR_TABLE
where
ISNUMERIC(intAllocatedResourceperDivision) = 1
UNION ALL
select
intAllocatedResourceperDivision
from
YOUR_TABLE
where
ISNUMERIC(intAllocatedResourceperDivision) = 0

This looks like SQL Server syntax. I would recommend using TRY_CONVERT():
TRY_CONVERT(DECIMAL, intAllocatedResourceperDivision) as intAllocatedResourceperDivision

Try this:
select 'CL' as intAllocatedResourceperDivision into #tmp
union select 'HS'union select 'HV'union select 'ML'union select 'SL'union select 'VL'union select 'HC'union select 'S'union select '*'union select '1'union select '4'
select CAST(SUM(ISNULL(CAST(intAllocatedResourceperDivision AS DECIMAL),0.00)) AS nvarchar(250)) as intAllocatedResourceperDivision
from #tmp where intAllocatedResourceperDivision NOT IN ('CL','HS','HV','ML','SL','VL','HC','S','*')
union
select intAllocatedResourceperDivision
from #tmp where intAllocatedResourceperDivision IN ('CL','HS','HV','ML','SL','VL','HC','S','*')

Related

Count of nulls and non-nulls in one Teradata query

in mySQL if I was looking to find the sum of null and non-null values for a column in one query, I can use
SELECT
SUM(col IS NOT NULL),
SUM(col IS NULL)
FROM test
However, the same syntax doesn't work in Teradata (Syntax error: expected something between the word 'col' and the 'IS' keyword.)
How can I adapt the above logic to Teradata?
Use CASE:
SELECT SUM(CASE WHEN col IS NOT NULL THEN 1 ELSE 0 END),
SUM(CASE WHEN col IS NULL THEN 1 ELSE 0 END)
FROM test;
Or, use COUNT():
SELECT COUNT(col),
COUNT(*) - COUNT(col)
FROM test;
Both of these are standard SQL and will work in any database.

multiple values to oracle case statement then

Can some one please explain how to pass multiple values to oracle case statement Then
SELECT *
FROM impl_debitor_information
WHERE soft_delete='F'
AND SHOP_ID ='4987bc1b-c0a8-6cb7-12f4-0243011f7099'
AND (debitor_type IS NULL
OR debitor_type IN (CASE
WHEN (SELECT techfund_debitor_enabled
FROM impl_shop
WHERE shop_id='4987bc1b-c0a8-6cb7-12f4-0243011f7099') = 'YES' THEN ('T','D')
ELSE 'D'
END))
If values from
select techfund_debitor_enabled from impl_shop where shop_id='4987bc1b-c0a8-6cb7-12f4-0243011f7099' is "YES" then I need to pass 2 values to in clause, if not single value
Thanks in advance
CASE will only return a single value. You must rewrite your query. Something like this:
SELECT *
FROM impl_debitor_information i, impl_shop where shop_id s
WHERE d.soft_delete='F'
AND d.shop_id ='4987bc1b-c0a8-6cb7-12f4-0243011f7099'
AND d.shop_id = s.shop_id
AND (d.debitor_type IS NULL
OR (d.debitor_type IN ('T','D') AND s.techfund_debitor_enabled = 'YES')
OR (d.debitor_type IN ('D') AND s.techfund_debitor_enabled <> 'YES'))
There might be errors in it, I didn't test the query.

PostgreSQL, SELECT CASE COALESCE

I need to 'name' categories: mycat is a text column with possible values '0' to '4'.
SELECT CASE mycat
WHEN '0' THEN 'ZERO'
WHEN '1' THEN 'ONE'
WHEN '2' THEN 'TWO'
WHEN '3' THEN 'THREE'
WHEN '4' THEN 'OTHER'
END AS my_category,
COALESCE(SUM(col1), 0),
COALESCE(SUM(col2), 0),
COALESCE(SUM(col3), 0)
FROM mytable
GROUP BY mycat
ORDER BY mycat;
That works OK, but I have some an error in my program which very rarely writes null (or '' as I can see in pgAdmin). In such cases I have to treat that '' the same as '0'.
But I can't get that!
I try like this:
SELECT CASE COALESCE(mycat, '0')
But this doesn't solve it at all.
How to get that '' will be summed and grouped together with '0' category?
PostgreSQL 9.3, Windows.
you need to use COALESCE in the group by and order by also similar to how you planned to change the case expression, but postgres is giving error , so another option is to wrap your statement in a subquery and do group by
SELECT my_category,
COALESCE(SUM(col1), 0),
COALESCE(SUM(col2), 0),
COALESCE(SUM(col3), 0)
FROM
(
SELECT CASE coalesce(mycat ,'0')
WHEN '0' THEN 'ZERO'
WHEN '1' THEN 'ONE'
WHEN '2' THEN 'TWO'
WHEN '3' THEN 'THREE'
WHEN '4' THEN 'OTHER'
WHEN '' THEN 'ZERO'
END AS my_category,
col1,
col2,
col3
FROM mytable
) T
GROUP BY my_category
ORDER BY my_category
You can have this without subquery. You could repeat the expression in the GROUP BY and ORDER BY clause. But it's much simpler to use the ordinal number of the output column instead:
SELECT CASE mycat
WHEN '1' THEN 'ONE'
WHEN '2' THEN 'TWO'
WHEN '3' THEN 'THREE'
WHEN '4' THEN 'OTHER'
ELSE 'ZERO' -- catches all other values
END AS my_category
, COALESCE(SUM(col1), 0) AS sum1
, COALESCE(SUM(col2), 0) AS sum2
, COALESCE(SUM(col3), 0) AS sum3
FROM mytable
GROUP BY 1
ORDER BY 1;
I chose the simplest and fastest code. The ELSE branch catches 0, '' and NULL - or any other value not yet filtered! But you say there are no others.
A couple of rants:
mycat is 'text' column with possible values '0' to '4'.
This is wrong in two ways.
Obviously, there are empty strings ('') and / or NULL values, too.
With that fixed, integer, smallint, of "char" with a CHECK cnstraint would be sensible choices for the data type. (Maybe even enum.) text, not so much.
To find out your actual range of values:
SELECT mycat, count(*) AS ct
FROM mytable
GROUP BY 1
ORDER BY 2 DESC;
If your client obfuscates NULL and empty values, test with mycat IS NULL. You need to know and understand the difference in many situations.
This orders by the resulting text in my_category like: ONE, OTHER, THREE, TWO, ZERO? I doubt you want that.

How to Convert these3 SQL queries into One?

Is there anyway i can convert the below 3 sql queries into a single query ?
insert into table1(Name,Age,Type) Select FirstName,Age,'Type1' FROM Table2 where Type='SK'
insert into table1(Name,Age,Type) Select FirstName,Age,'Type23' FROM Table2 where Type='JK'
insert into table1(Name,Age,Type) Select FirstName,45,'Type64' FROM Table2 where Type='YP'
insert into table1(Name,Age,Type)
Select FirstName,Age,'Type1' FROM Table2 where Type='SK'
union all
Select FirstName,Age,'Type23' FROM Table2 where Type='JK'
union all
Select FirstName,45,'Type64' FROM Table2 where Type='YP'
insert into table1(Name,Age,Type)
Select FirstName,
CASE WHEN Type = 'YP' THEN 45 ELSE Age END,
CASE WHEN Type = 'SK' THEN 'Type1' etc.
FROM Table2
where Type in ('SK', 'JK', 'YP')
EDIT:
It depends here how many types there are. Maybe another table that stores the types and the correpsonding texts ('Type' etc.) would be better instead of a huge case. And same thing for the age.
Try:
Insert table1(Name,Age,Type)
Select FirstName,
Case Type When 'YP' Then 45 Else Age End,
'Type' + Case Type
When 'SK' Then '1'
When 'JK' Then '23'
When 'YP' Then '64' End
From Table2
Where Type In ('SK', 'JK', 'YP')
Try..
insert into table1(Name,Age,Type)
(Select FirstName,
(case when type='YP' then
45
else
age
end) age,
(case when type='SK' then
'Type1'
when type='JK' then
'Type23'
when type='YP' then
'Type64'
end) type
FROM Table2 where Type in ('SK','JK','YP'))

Counting null and non-null values in a single query

I have a table
create table us
(
a number
);
Now I have data like:
a
1
2
3
4
null
null
null
8
9
Now I need a single query to count null and not null values in column a
This works for Oracle and SQL Server (you might be able to get it to work on another RDBMS):
select sum(case when a is null then 1 else 0 end) count_nulls
, count(a) count_not_nulls
from us;
Or:
select count(*) - count(a), count(a) from us;
If I understood correctly you want to count all NULL and all NOT NULL in a column...
If that is correct:
SELECT count(*) FROM us WHERE a IS NULL
UNION ALL
SELECT count(*) FROM us WHERE a IS NOT NULL
Edited to have the full query, after reading the comments :]
SELECT COUNT(*), 'null_tally' AS narrative
FROM us
WHERE a IS NULL
UNION
SELECT COUNT(*), 'not_null_tally' AS narrative
FROM us
WHERE a IS NOT NULL;
Here is a quick and dirty version that works on Oracle :
select sum(case a when null then 1 else 0) "Null values",
sum(case a when null then 0 else 1) "Non-null values"
from us
for non nulls
select count(a)
from us
for nulls
select count(*)
from us
minus
select count(a)
from us
Hence
SELECT COUNT(A) NOT_NULLS
FROM US
UNION
SELECT COUNT(*) - COUNT(A) NULLS
FROM US
ought to do the job
Better in that the column titles come out correct.
SELECT COUNT(A) NOT_NULL, COUNT(*) - COUNT(A) NULLS
FROM US
In some testing on my system, it costs a full table scan.
As i understood your query, You just run this script and get Total Null,Total NotNull rows,
select count(*) - count(a) as 'Null', count(a) as 'Not Null' from us;
usually i use this trick
select sum(case when a is null then 0 else 1 end) as count_notnull,
sum(case when a is null then 1 else 0 end) as count_null
from tab
group by a
Just to provide yet another alternative, Postgres 9.4+ allows applying a FILTER to aggregates:
SELECT
COUNT(*) FILTER (WHERE a IS NULL) count_nulls,
COUNT(*) FILTER (WHERE a IS NOT NULL) count_not_nulls
FROM us;
SQLFiddle: http://sqlfiddle.com/#!17/80a24/5
This is little tricky. Assume the table has just one column, then the Count(1) and Count(*) will give different values.
set nocount on
declare #table1 table (empid int)
insert #table1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(NULL),(11),(12),(NULL),(13),(14);
select * from #table1
select COUNT(1) as "COUNT(1)" from #table1
select COUNT(empid) "Count(empid)" from #table1
Query Results
As you can see in the image, The first result shows the table has 16 rows. out of which two rows are NULL. So when we use Count(*) the query engine counts the number of rows, So we got count result as 16. But in case of Count(empid) it counted the non-NULL-values in the column empid. So we got the result as 14.
so whenever we are using COUNT(Column) make sure we take care of NULL values as shown below.
select COUNT(isnull(empid,1)) from #table1
will count both NULL and Non-NULL values.
Note: Same thing applies even when the table is made up of more than one column. Count(1) will give total number of rows irrespective of NULL/Non-NULL values. Only when the column values are counted using Count(Column) we need to take care of NULL values.
I had a similar issue: to count all distinct values, counting null values as 1, too. A simple count doesn't work in this case, as it does not take null values into account.
Here's a snippet that works on SQL and does not involve selection of new values.
Basically, once performed the distinct, also return the row number in a new column (n) using the row_number() function, then perform a count on that column:
SELECT COUNT(n)
FROM (
SELECT *, row_number() OVER (ORDER BY [MyColumn] ASC) n
FROM (
SELECT DISTINCT [MyColumn]
FROM [MyTable]
) items
) distinctItems
Try this..
SELECT CASE
WHEN a IS NULL THEN 'Null'
ELSE 'Not Null'
END a,
Count(1)
FROM us
GROUP BY CASE
WHEN a IS NULL THEN 'Null'
ELSE 'Not Null'
END
Here are two solutions:
Select count(columnname) as countofNotNulls, count(isnull(columnname,1))-count(columnname) AS Countofnulls from table name
OR
Select count(columnname) as countofNotNulls, count(*)-count(columnname) AS Countofnulls from table name
Try
SELECT
SUM(ISNULL(a)) AS all_null,
SUM(!ISNULL(a)) AS all_not_null
FROM us;
Simple!
If you're using MS Sql Server...
SELECT COUNT(0) AS 'Null_ColumnA_Records',
(
SELECT COUNT(0)
FROM your_table
WHERE ColumnA IS NOT NULL
) AS 'NOT_Null_ColumnA_Records'
FROM your_table
WHERE ColumnA IS NULL;
I don't recomend you doing this... but here you have it (in the same table as result)
use ISNULL embedded function.
All the answers are either wrong or extremely out of date.
The simple and correct way of doing this query is using COUNT_IF function.
SELECT
COUNT_IF(a IS NULL) AS nulls,
COUNT_IF(a IS NOT NULL) AS not_nulls
FROM
us
SELECT SUM(NULLs) AS 'NULLS', SUM(NOTNULLs) AS 'NOTNULLs' FROM
(select count(*) AS 'NULLs', 0 as 'NOTNULLs' FROM us WHERE a is null
UNION select 0 as 'NULLs', count(*) AS 'NOTNULLs' FROM us WHERE a is not null) AS x
It's fugly, but it will return a single record with 2 cols indicating the count of nulls vs non nulls.
This works in T-SQL. If you're just counting the number of something and you want to include the nulls, use COALESCE instead of case.
IF OBJECT_ID('tempdb..#us') IS NOT NULL
DROP TABLE #us
CREATE TABLE #us
(
a INT NULL
);
INSERT INTO #us VALUES (1),(2),(3),(4),(NULL),(NULL),(NULL),(8),(9)
SELECT * FROM #us
SELECT CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END AS 'NULL?',
COUNT(CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END) AS 'Count'
FROM #us
GROUP BY CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END
SELECT COALESCE(CAST(a AS NVARCHAR),'NULL') AS a,
COUNT(COALESCE(CAST(a AS NVARCHAR),'NULL')) AS 'Count'
FROM #us
GROUP BY COALESCE(CAST(a AS NVARCHAR),'NULL')
Building off of Alberto, I added the rollup.
SELECT [Narrative] = CASE
WHEN [Narrative] IS NULL THEN 'count_total' ELSE [Narrative] END
,[Count]=SUM([Count]) FROM (SELECT COUNT(*) [Count], 'count_nulls' AS [Narrative]
FROM [CrmDW].[CRM].[User]
WHERE [EmployeeID] IS NULL
UNION
SELECT COUNT(*), 'count_not_nulls ' AS narrative
FROM [CrmDW].[CRM].[User]
WHERE [EmployeeID] IS NOT NULL) S
GROUP BY [Narrative] WITH CUBE;
SELECT
ALL_VALUES
,COUNT(ALL_VALUES)
FROM(
SELECT
NVL2(A,'NOT NULL','NULL') AS ALL_VALUES
,NVL(A,0)
FROM US
)
GROUP BY ALL_VALUES
select count(isnull(NullableColumn,-1))
if its mysql, you can try something like this.
select
(select count(*) from TABLENAME WHERE a = 'null') as total_null,
(select count(*) from TABLENAME WHERE a != 'null') as total_not_null
FROM TABLENAME
Just in case you wanted it in a single record:
select
(select count(*) from tbl where colName is null) Nulls,
(select count(*) from tbl where colName is not null) NonNulls
;-)
for counting not null values
select count(*) from us where a is not null;
for counting null values
select count(*) from us where a is null;
I created the table in postgres 10 and both of the following worked:
select count(*) from us
and
select count(a is null) from us
In my case I wanted the "null distribution" amongst multiple columns:
SELECT
(CASE WHEN a IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS a_null,
(CASE WHEN b IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS b_null,
(CASE WHEN c IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS c_null,
...
count(*)
FROM us
GROUP BY 1, 2, 3,...
ORDER BY 1, 2, 3,...
As per the '...' it is easily extendable to more columns, as many as needed
Number of elements where a is null:
select count(a) from us where a is null;
Number of elements where a is not null:
select count(a) from us where a is not null;