SQL - Group based on multi - columns - sql-server

I have table like the following :
A_ID Area_Code Status
1 AAA 2
2 BBB 1
3 AAA 2
4 AAA 3
5 AAA 2
6 BBB 2
7 BBB 1
8 AAA 4
9 AAA 5
10 AAA 4
And i want the result set like :
A_Code Count_A_Code Count_Sts1 Count_Sts2 Count_Sts3 Count_Sts4 Count_Sts5
AAA 7 0 3 1 2 1
BBB 3 2 1 0 0 0
Please note that i have only 5 statues . so i need the statues to be columns ..
I appreciate any help . thanks

select area_code as a_code,
count(*) as count_a_code,
sum(case when status = 1 then 1 else 0 end) as code_count_sts1,
sum(case when status = 2 then 1 else 0 end) as code_count_sts2,
sum(case when status = 3 then 1 else 0 end) as code_count_sts3,
sum(case when status = 4 then 1 else 0 end) as code_count_sts4,
sum(case when status = 5 then 1 else 0 end) as code_count_sts5
from your_table
group by area_code

Related

Select data from previous rows with condition

My data looks like this
col1; col2; col3; col4; sort; desc; levels
1 1 1 1 10 ab null
1 1 1 2 20 c 1
1 1 1 3 30 d null
1 1 1 4 40 e null
1 1 1 5 50 fg 1
1 1 1 6 60 hij 1
1 1 1 7 70 k 1
The desired output looks like this
col1; col2; col3; col4; desc; addDesc
1 1 1 1 ab null
1 1 1 2 c ab
1 1 1 3 d null
1 1 1 4 e null
1 1 1 5 fg e
1 1 1 6 hij e
1 1 1 7 k e
The logic is whenever the column LEVELS is not null, take the value from previous DESC where LEVELS is null.
I hope you guys understand this!
Thank you all in advance!
You can use OUTER APPLY:
SELECT t1.col1,
t1.col2,
t1.col3,
t1.col4,
t1.[desc],
CASE
WHEN t1.levels IS NOT NULL THEN t2.[desc]
END [addDesc]
FROM dbo.YourTable t1
OUTER APPLY (SELECT TOP 1 [desc]
FROM dbo.YourTable
WHERE levels IS NULL
AND sort < t1.sort
ORDER BY sort DESC) t2;

SQL query to get Groups and sub groups hierarchy

Account table
ac_id ac_name st_id
----------- ------------- -----------
1 LIABILITES 1
2 ASSET 1
3 REVENUE 1
4 EXPENSES 1
5 EQUITY 1
Groups table
grp_id grp_name ac_no grp_of st_id type_ cmp_id
----------- ------------------- ---------- -------- --------- --------- --------
1 Capital Account 1 0 1 0 0
2 Current Liability 1 0 1 0 0
3 Loan Liability 1 0 1 0 0
4 Suspense A/C 1 0 1 0 0
5 Current Assets 2 0 1 0 0
6 Fixed Assests 2 0 1 0 0
7 Investment 2 0 1 0 0
8 Misc. Expenses 2 0 1 0 0
9 Direct Income 3 0 1 0 0
10 Indirect Income 3 0 1 0 0
11 Sale Account 3 0 1 0 0
12 Direct Expense 4 0 1 0 0
13 Indirect Expense 4 0 1 0 0
14 Purchase Account 4 0 1 0 0
15 Sundry Creditors 2 1 1 0 0
16 Sundry Debitors 5 1 1 0 0
17 Bank Account 5 1 1 0 0
18 Cash In Hand 5 1 1 0 0
19 Duties & Taxes 2 1 1 0 0
20 Salary 12 1 1 0 0
21 Personal 5 1 1 0 0
22 Loan 2 0 1 0 0
23 Customer 16 1 1 0 0
34 Vendor 15 1 1 0 0
38 Sale Softwares 11 1 1 1 1
46 Stock In Hand 5 1 1 1 1
47 test 1 1 1 1 1
48 test in 47 1 1 1 1
Query to get all groups hierarchy.
declare #ac_no as int =2
;With CTE(grp_id,grp_name,ac_no,Level)
AS
( SELECT
grp_id,grp_name,ac_no,CAST(1 AS int)
FROM
Groups
WHERE
grp_id in (select grp_id from Groups where (ac_no=#ac_no) and grp_of=0)
UNION ALL
SELECT
o.grp_id,o.grp_name,o.ac_no,c.Level+1
FROM
Groups o
INNER JOIN
CTE c
ON c.grp_id=o.ac_no --where o.ac_no=2 and o.grp_of=1
)
select * from CTE
Result is ok for ac_no=2/3/4
grp_id grp_name ac_no Level
----------- ------------------- ----------- ------
5 Current Assets 2 1
6 Fixed Assests 2 1
7 Investment 2 1
8 Misc. Expenses 2 1
22 Loan 2 1
16 Sundry Debitors 5 2
17 Bank Account 5 2
18 Cash In Hand 5 2
21 Personal 5 2
46 Stock In Hand 5 2
23 Customer 16 3
But when I try to get result for ac_no=1;
I get error :
Msg 530, Level 16, State 1, Line 4
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
I think the issue is that you end up in an infinite recursion as you have a row that is it's own parent/child (eg. grp_id = ac_no).
I think it should work if you add a limiting clause to the recursive member like this:
DECLARE #ac_no AS int = 1;
WITH CTE (grp_id , grp_name , ac_no , Level ) AS (
SELECT grp_id, grp_name, ac_no, CAST( 1 AS int )
FROM Groups
WHERE grp_id IN (SELECT grp_id FROM Groups WHERE ac_no = #ac_no AND grp_of = 0)
UNION ALL
SELECT o.grp_id, o.grp_name, o.ac_no, c.Level + 1
FROM Groups o
INNER JOIN CTE c ON c.grp_id = o.ac_no --where o.ac_no=2 and o.grp_of=1
WHERE c.ac_no <> c.grp_id
)
SELECT * FROM CTE;

Count and Group By for products sold

I have a table Transaction & a table product as below .
Each Transaction has multiple products.
ProductId Name
1 ABC
2 DEF
3 GHI
Each transaction can have multiple products sold.
TransactionId ProductSoldInDept1 ProductSoldinDept2 ProductSoldinDept3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
I am planning to generate a report and I would like to get a result something like this :
This shows the number of products sold per each department grouped by Id
Expected Result :
ProductID Department1ProdCount Department2ProdCount Department3ProdCount
1 2 1 1
2 1 1 0
3 1 1 0
I could get till here , this is a query to get the counts for one specific product
which is productid : 1
I would like to know how I could use a group by here :
select Count(CASE WHEN ProductSoldInDept1 = 1 THEN 1 END) ,
Count(CASE WHEN ProductSoldInDept2 = 1 THEN 1 END) ,
Count(CASE WHEN ProductSoldInDept3 = 1 THEN 1 END)
from Table1
SELECT
p.ProductID,
Dept1ProdCount = COUNT(CASE WHEN t.ProductSoldInDept1 = p.ProductID THEN 1 END),
Dept2ProdCount = COUNT(CASE WHEN t.ProductSoldInDept2 = p.ProductID THEN 1 END),
Dept3ProdCount = COUNT(CASE WHEN t.ProductSoldInDept3 = p.ProductID THEN 1 END)
FROM dbo.Product AS p
LEFT OUTER JOIN dbo.[Transaction] AS t
ON p.ProductID IN
(t.ProductSoldInDept1, t.ProductSoldinDept2, t.ProductSoldinDept3)
GROUP BY p.ProductID;
Result
| PRODUCTID | DEPT1PRODCOUNT | DEPT2PRODCOUNT | DEPT3PRODCOUNT |
----------------------------------------------------------------
| 1 | 2 | 1 | 1 |
| 2 | 1 | 1 | 0 |
| 3 | 1 | 1 | 0 |
See a demo
Try this
select ProductID,
v.Department1ProdCount, v.Department2ProdCount, v.Department3ProdCount
from product a
cross apply
(
select Count(CASE WHEN ProductSoldInDept1 = a.ProductID THEN 1 END) Department1ProdCount,
Count(CASE WHEN ProductSoldInDept2 = a.ProductID THEN 1 END) Department2ProdCount,
Count(CASE WHEN ProductSoldInDept3 = a.ProductID THEN 1 END) Department3ProdCount
from Table1
) v
This:
TransactionId ProductSoldInDept1 ProductSoldinDept2 ProductSoldinDept3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
might be better structured as this:
transid prodsold deptid
1 1 1
2 1 1
2 2 2
3 3 1
3 1 2
4 2 1
4 3 2
4 1 3
I think that would make your queries easier to write.

SQL to combine data for single row per object

I know this must be a common problem, but I'm not sure where to go. This occurs a few times inside a big nasty query, so here is the problem simplified. I just want one row per object, but the null on ColorOther gives me two rows.
I can think of a few things to try wrapping a query around this, but there must be something simpler... I'm off to read up on pivots.
Table structure
CREATE TABLE [dbo].[Colors](
[ColorId] [int] IDENTITY(1,1) NOT NULL,
[ColoredObjectId] [int] NOT NULL,
[ColorCode] [int] NOT NULL,
[ColorOther] [nvarchar](50) NULL,
CONSTRAINT [PK_Colors] PRIMARY KEY CLUSTERED
([ColorId] ASC)
Source data
ColorId ColoredObjectId ColorCode ColorOther
----------- --------------- ----------- ----------
1 1 1 NULL
2 1 2 NULL
3 1 4 purple
4 2 2 NULL
5 2 3 NULL
6 2 4 orange
7 3 1 NULL
8 3 3 NULL
9 3 4 green
Query
SELECT ColoredObjectId ,
ColorOther ,
MAX(CASE WHEN ColorCode = 1 THEN 1 ELSE 0 END) AS Yellow,
MAX(CASE WHEN ColorCode = 2 THEN 1 ELSE 0 END) AS Red ,
MAX(CASE WHEN ColorCode = 3 THEN 1 ELSE 0 END) AS Blue ,
MAX(CASE WHEN ColorCode = 4 THEN 1 ELSE 0 END) AS Other
FROM Colors
GROUP BY ColoredObjectId,
ColorOther
Output
ColoredObjectId ColorOther Yellow Red Blue Other
--------------- ---------- ----------- ----------- ----------- -----------
1 NULL 1 1 0 0
1 purple 0 0 0 1
2 NULL 0 1 1 0
2 orange 0 0 0 1
3 NULL 1 0 1 0
3 green 0 0 0 1
Desired output
ColoredObjectId ColorOther Yellow Red Blue Other
--------------- ---------- ----------- ----------- ----------- -----------
1 purple 1 1 0 1
2 orange 0 1 1 1
3 green 1 0 1 1
I think this should return the desired output.
SELECT ColoredObjectId ,
MAX(ColorOther) AS ColorOther ,
MAX(CASE WHEN ColorCode = 1 THEN 1 ELSE 0 END) AS Yellow,
MAX(CASE WHEN ColorCode = 2 THEN 1 ELSE 0 END) AS Red ,
MAX(CASE WHEN ColorCode = 3 THEN 1 ELSE 0 END) AS Blue ,
MAX(CASE WHEN ColorCode = 4 THEN 1 ELSE 0 END) AS Other
FROM Colors
GROUP BY ColoredObjectId
Try this (I am not at a SQL box, so I can't test it, but it should be pretty close)
SELECT cc.ColoredObjectId ,
xx.ColorOther ,
MAX(CASE WHEN ColorCode = 1 THEN 1 ELSE 0 END) AS Yellow,
MAX(CASE WHEN ColorCode = 2 THEN 1 ELSE 0 END) AS Red ,
MAX(CASE WHEN ColorCode = 3 THEN 1 ELSE 0 END) AS Blue ,
MAX(CASE WHEN ColorCode = 4 THEN 1 ELSE 0 END) AS Other
FROM Colors cc
JOIN (select distinct ColorObjectID,ColorOther FROM colors
where colorOther is not null) xx on xx.colorObjectId=cc.colorobjectID
GROUP BY cc.ColoredObjectId,
xx.ColorOther

Pivot/aggregation with percentage columns possible in t-sql?

Struggling with this a bit in SQL Server, any ideas? Given this data (ID is an INT, the rest are BITs):
------------------------------------------
ID Type1 Type2 AttrA AttrB AttrC
------------------------------------------
1 1 0 1 0 0
2 1 0 1 0 0
3 1 1 0 1 1
4 0 1 1 1 0
5 1 1 1 1 0
I would like to produce this report:
---------------------------------------------------------
Attr NumOfType1 PctOfType1 NumOfType2 PctOfType2
---------------------------------------------------------
AttrA 3 75% 2 67%
AttrB 2 50% 3 100%
AttrC 1 25% 1 33%
Total 4 N/A 3 N/A
Thanks!
Jim
;WITH YourBaseTable AS
(
SELECT 1 ID, 1 Type1,0 Type2, 1 AttrA, 0 AttrB, 0 AttrC UNION ALL
SELECT 2 ID, 1 Type1,0 Type2, 1 AttrA, 0 AttrB, 0 AttrC UNION ALL
SELECT 3,1,1,0,1,1 UNION ALL
SELECT 4,0,1,1,1,0 UNION ALL
SELECT 5,1,1,1,1,0
), T AS
(
SELECT *, 1 AS Total
FROM YourBaseTable
)
SELECT
Attr,
COUNT(CASE WHEN VALUE = 1 AND Type1 = 1 THEN 1 END) NumOfType1,
CASE WHEN Attr <> 'Total' THEN 100 * CAST(COUNT(CASE WHEN VALUE = 1 AND Type1 = 1 THEN 1 END) AS FLOAT)/COUNT(CASE WHEN Type1 = 1 THEN 1 END) END PctOfType1,
COUNT(CASE WHEN VALUE = 1 AND Type2 = 1 THEN 1 END) NumOfType2,
CASE WHEN Attr <> 'Total' THEN 100 * CAST(COUNT(CASE WHEN VALUE = 1 AND Type2 = 1 THEN 1 END) AS FLOAT)/COUNT(CASE WHEN Type2 = 1 THEN 1 END) END PctOfType2
FROM T
UNPIVOT
(VALUE FOR Attr IN (AttrA, AttrB,AttrC, Total)) AS unpvt
GROUP BY Attr

Resources