group by JSON Column that contains an array - sql

I have the following table:
that contains these data:
How can I group by my array items in my JSON Column? and get this result:

You can try to use OPENJSON with CROSS APPLY to make it.
SELECT
col1,
UserID
FROM T t1
CROSS APPLY
OPENJSON(t1.Roles)
WITH
(
col1 varchar(50) N'$'
) AS a
sqlfiddle

If you cannot use OPENJSON, here is an alternative
Select
aRole, COUNT(*) as cnt
From (
Select
a.ID
,b.Items as aRole
From
(Select *
,replace(replace(replace(Roles,'[',''),']',''),'"','') as Rolesx
From JSONgroup) a
Cross Apply dbo.Split(a.Rolesx, ',') b
) c
group by aRole

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

How to Split two column in same table in SQL Sever

Declare #abc varchar(max)='5,4,1',
#xyz varchar(max)='1,2,3';
select value[A] from string_split(#abc,',')
select value[B] from string_split(#xyz,',')
I need this result in same table
A B
5 1
4 2
1 3
You may use row_number() to give unique number to each record of your string, then apply join on behalf of that generated row_number().
Sample is like this.
select [A], [B] from
(
select row_number() over (order by (select 100)) as Slno, value as [A] from string_split(#abc,',')
) as t1
full outer join
(
select row_number() over (order by (select 100)) as Slno, value as [B] from string_split(#xyz,',')
) as t2
on t1.slno=t2.slno

Select count(*) from table where (multiple id) in (table)

Is there a way to write
SELECT count(*) from tablename where (multiple_ids_here) in (SELECT id from tablename)
Normally, I would write:
select count(*) from tablename
where id_1 in (SELECT id from tablename)
OR id_2 in (SELECT id from tablename)
id_3 in (SELECT id from tablename)
which very inefficient if we have multiple values.
Anyone?
EDIT: Question updated. What if I want to select count?
Your version with three ins is probably the most efficient way of doing this. If you want a comparison to try, you can use exists:
select . . .
from t t1
where exists (select 1
from tablename t2
where t2.id in (t1.id_1, t1.id_2, t1.id_3)
);
I should also note that storing ids in multiple columns like this is usually a sign of a problem with the data model. You probably want a table with one row per id, rather than one column per id. Such a format would also simplify this type of query.
For the updated question regarding getting a count(*)... using cross apply() with values() to unpivot your data in a common table expression:
;with cte as (
select t.Id, v.RelatedId
from t
cross apply (values (id_1),(id_2),(id_3)) v(RelatedId)
)
select
cte.Id
, RelationCount = count(*)
from cte
inner join RelatedTable r
on cte.RelatedId = r.Id
group by cte.Id
I am not sure i understand your question could you give an example of the data you are using and the out come.
From what i understand you could use a cte like this .
;WITH Sales_CTE ([counts],CustomerID, SalespersonPersonID,PickedByPersonID)
AS
(
select count(*),CustomerID,SalespersonPersonID ,PickedByPersonID
from [WideWorldImporters].[Sales].[Orders]
group by CustomerID,SalespersonPersonID,PickedByPersonID
)
SELECT sum([counts])
FROM Sales_CTE
GO
It would give you a result like this . You would jsut have to change the columns around .

SQL - Pivot 2 columns

I have the following sql
CREATE TABLE #t ( id varchar(10)
,Rscd varchar(10)
,Accd varchar(10))
INSERT INTO #t Values ('EHC','A','B')
INSERT INTO #t Values ('DEN','C','D')
select EHC,DEN
from
(
select id as id2, value
from #t
cross apply
(
select id,Rscd union select id,Accd
) c (id2,value)
) d
pivot
(
max(value)
for id2 in ([EHC],[DEN])
) piv;
This produce output as
EHC DEN
B D
But I need the Out put as
EHC DEN EHC2 DEN2
B D A C
Is this possible ? Thanks for you assistance.
You need to implement a windowing function like row_number() to get the result. This will create a sequence number based on the id. It appears that you have a specific order that you want the data in, if so then I would create a column when you are unpivoting via CROSS APPLY that will be used to order the data:
select EHC1,DEN1, EHC2, DEN2
from
(
select value,
id2 = id
+ cast(row_number() over(partition by id
order by so desc) as varchar(10))
from #t
cross apply
(
select id, Rscd, 1 union
select id, Accd, 2
) c (id2,value, so)
) d
pivot
(
max(value)
for id2 in ([EHC1],[DEN1], [EHC2],[DEN2])
) piv;
See SQL Fiddle with Demo

How to get Original Rows filtered by a HAVING Condition?

What is the method in T-SQL to select the orginal values limited by a HAVING attribute. For example, if I have
A|B
10|1
11|2
10|3
How would I get all the values of B (Not An Average or some other summary stat), Grouped by A, having a Count (Occurrences of A) greater than or equal two 2?
Actually, you have several options to choose from
1. You could make a subquery out of your original having statement and join it back to your table
SELECT *
FROM YourTable yt
INNER JOIN (
SELECT A
FROM YourTable
GROUP BY
A
HAVING COUNT(*) >= 2
) cnt ON cnt.A = yt.A
2. another equivalent solution would be to use a WITH clause
;WITH cnt AS (
SELECT A
FROM YourTable
GROUP BY
A
HAVING COUNT(*) >= 2
)
SELECT *
FROM YourTable yt
INNER JOIN cnt ON cnt.A = yt.A
3. or you could use an IN statement
SELECT *
FROM YourTable yt
WHERE A IN (SELECT A FROM YourTable GROUP BY A HAVING COUNT(*) >= 2)
A self join will work:
select B
from table
join(
select A
from table
group by 1
having count(1)>1
)s
using(A);
You can use window function (no joins, only one table scan):
select * from (
select *, cnt=count(*) over(partiton by A) from table
) as a
where cnt >= 2