SQL: Count of items in comma-separated column in a table - sql

Column1
--------
1,2,4
2,3,5
2,1,3
I have a column in a table which is comma-separated as shown above. From which I need to get below output:
No Count
----------
1 2
2 3
3 2
4 1
When I tried with
SELECT SUM(LEN(Holidays) - LEN(REPLACE(Holidays, ',', '')) + 1)
FROM [dbo].[OhLog]
I'm not getting item wise count. Instead it is getting full count.

You can use CROSS_APPLY with STRING_SPLIT to create rows from the comma separated data values, and then COUNT the occurrences of each value:
SELECT value as [Holiday], COUNT(*) AS [Count]
FROM OhLog
CROSS APPLY STRING_SPLIT([Holidays], ',')
GROUP BY value
Output:
Holiday Count
1 2
2 3
3 2
4 1
5 1
Demo on dbfiddle
If your database compatibility version is not at least 130, you won't have access to STRING_SPLIT. You can modify the compatibility version as described in the manual, or alternatively, use this query (based on this answer):
SELECT [Holiday], COUNT(*) AS [Count]
FROM (SELECT Split.a.value('.', 'NVARCHAR(MAX)') [Holiday]
FROM (SELECT CAST('<X>'+REPLACE([Holidays], ',', '</X><X>')+'</X>' AS XML) AS String
FROM Ohlog
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)) AS O
GROUP BY [Holiday]
Output is the same as for the prior query. Demo on dbfiddle

Please try:
SELECT
Num, count(*) Cnt from
(
SELECT
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Num
FROM
(
SELECT CAST('<XMLRoot><RowData>' + REPLACE(Column1,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM tbl
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
)x
GROUP BY Num
Demo Result

So, you can use STRING_SPLIT function. It is supported by Sql Server 2017.
more info here http://www.sqlservertutorial.net/sql-server-string-functions/sql-server-string_split-function/
It creates a table from string.
So, for each row in DB you will get a table. To Union it into one common table you have to use CROSS APPLY.
SELECT VALUE, COUNT(*) FROM test_for_parse CROSS APPLY STRING_SPLIT(array_value,',') GROUP BY VALUE
So, here is an example of code, that emulate your situation.
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=8393f8dab667b528ed5aad7c61da74fe

Related

Concatenating Column Values into a Comma-Separated List in SQL Server

What is the T-SQL syntax to format my output so that the column values appear as a string, separated by commas?
For example, my table Rating have the following:
MbrID
Grade
Rating
1
A
12,13
1
B
10,15
1
C
7,3
How do I get the output as
MbrID
FinalRating
1
A12,A13,B10,B15,C7,C3
One option is using string_agg() in concert with a little string manipulation within a CROSS APPLY
Example or dbFiddle
Select MbrID
,NewValue = string_agg(V,',')
from YourTable A
Cross Apply ( values (Grade + replace(rating,',',','+Grade) ) )B(V)
Group By MbrID
Results
MbrID NewValue
1 A12,A13,B10,B15,C7,C3
Update: 2016 approach
;with cte as (
Select A.MbrID
,B.V
from YourTable A
Cross Apply ( values (Grade + replace(rating,',',','+Grade) ) )B(V)
)
Select MbrID
,FinalRating = stuff((Select ',' +V From CTE Where [MbrID]=A.[MbrID] For XML Path ('')),1,1,'')
From cte A
Group By MbrID

Redshift SQL - Reverse Listagg function

Suppose I have a table like below:
Name Order
AA 1,2
BB 2,3
I want my result to be like:
Name Order
AA 1
AA 2
BB 2
BB 3
How can I achieve this in Redshift?
Thanks!
Assuming that you know in advance the maximum number of elements per delimited list, you can do this with a table of numbers and split_part():
select t.name, split_part(t.order, ',', n.n) val
from (
select 1 n
union all select 2
union all select 3
) n
inner join mytable t
on n.n <= regexp_count(t.order, ',') + 1
you can expand derived table n with more numbers as needed. It is also possible to use row_number() against a large table to generate the numbers table.

SQL : How to find the count of an particular category values from an column with string values

I have a SQL Table called "category" looks like this
id | category
--------------
1 | 3,2
2 | 1
3 | 4,3,2
4 | 2,1
5 | 1,4
6 | 2,3,4
There are multiple category id's in the column "category", I need to find the count of an particular category values.
Current method I am using is:
select count(distinct(Category)) AS coldatacount from table_name
It gives the count of all the distinct values WHERE as I need to get
the count of all the particular category_id's separately.
if you are trying to get the Category Ids in comma delimited, you can use the string_split function to get distinct category_id
with cte as (
select 1 as id, '3,2' as category union all
select 2, '1' union all
select 3, '4,3,2' union all
select 4, '2,1' union all
select 5, '1,4' union all
select 6, '2,3,4'
)select count(distinct(value)) as category from cte
cross apply string_split(cte.category, ',');
I assumed that #neeraj04 may be looking for count of all Id in the category, continuing with #METAL code:
CREATE TABLE YourTable
(
Id INT IDENTITY,
[Category] VARCHAR(50)
);
INSERT YourTable VALUES ('3,2'), ('1'), ('4,3,2'), ('2,1'), ('1,4'), ('2,3,4');
SELECT CAST(value AS INT) AS category -- Value is string ouptut
, COUNT([value]) AS IdCount
FROM YourTable yt
CROSS APPLY string_split(yt.Category, ',')
GROUP BY [value]
ORDER BY category;
This is a horrible data model. You should not be storing multiple values in a string. You should not be storing numbers as strings.
Sometimes we are stuck with other people's really, really bad decisions. One approach is to split the string and count:
select t.*, cnt
from t cross apply
(select count(*) as cnt
from string_split(t.category) s
) s;
The other is to count commas:
select t.*,
(1 + len(t.category) - len(replace(t.category, ',', '')) as num_elements
Select Count(Value) from (Select Value from Table_Name a Cross Apply
string_split(a.Category, ','))ab Where Value=1

use distinct and order by in STRING_AGG function

I am trying the string_agg a column while at the same time ordering the column and only show unique values. Consider the following demo. IS there a syntax issue or is this simply not possible with the method I am using?
SELECT STRING_AGG(DISTINCT foo.a::TEXT,',' ORDER BY foo.a DESC)
FROM (
SELECT 1 As a
UNION ALL
SELECT 1
UNION ALL
SELECT 1
UNION ALL
SELECT 2
) AS foo
[2019-11-22 13:29:32] [42P10] ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list
[2019-11-22 13:29:32] Position: 53
The error message is quite clear. The expression that you use in the ORDER BY clause must also appear in the aggregated part.
You could do:
SELECT STRING_AGG(DISTINCT foo.a::TEXT, ',' ORDER BY foo.a::TEXT DESC)
FROM (
SELECT 1 As a
UNION ALL SELECT 1
UNION ALL SELECT 1
UNION ALL SELECT 2
) AS foo
Demo on DB Fiddle
While this will work, the problem with this solution is that it will order numbers as strings, that do not have the same ordering rules. String wise, 10 is less than 2.
Another option is to use arrays: first, ARRAY_AGG() can be used to aggregate the numbers (with proper, numeric ordering), then you can turn it to a comma-separated list of strings with ARRAY_TO_STRING().
SELECT ARRAY_TO_STRING(ARRAY_AGG(DISTINCT a ORDER BY a DESC), ',')
FROM (
SELECT 1 As a
UNION ALL SELECT 1
UNION ALL SELECT 1
UNION ALL SELECT 2
) AS foo
Demo on DB Fiddle

How to show query result in group? SQL Query

Right now my sql query display the result as follows.
though it is the correct result.
I prefer to have the have the result to show as follows.
How can I do this with SQL ? I am on SQL server 2008
I'm with the commenters, better to do this elsewhere, but it's simple enough in SQL using a CASE statement and the ROW_NUMBER() function:
;WITH cte AS (SELECT *,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT 1)) RN
FROM YourTable)
SELECT CASE WHEN RN = 1 THEN CAST(ID AS VARCHAR(5)) ELSE '' END, Name
FROM cte
ORDER BY ID,RN
Demo: SQL Fiddle
This is not a job for SQL.
Any way, you can easily display it with comma separated values:
ID Names
1000 Honda, Toyota,...
1000 Honda, Toyota,...
SELECT ID, Names=
STUFF((SELECT ', ' + Name
FROM your_table b
WHERE b.ID= a.ID
FOR XML PATH('')), 1, 2, '')
FROM your_table a
GROUP BY ID