SQL Pivot MIN( COUNT ( - sql-server

I have a complicated MS SQL 2005 query with a PIVOT in it...
I have data like this :
Data ( clients left join visits ):
ClientID VisitID ServiceID
1 34 5
1 36 2
1 36 5
1 45 2
1 48 2
1 60 2
2 44 1
3 48 2
3 78 3
3 79 2
And what I need is this:
ID [1] [2] [3] [4] [5]
1 0 1 0 0 1
2 1 0 0 0 0
3 0 1 1 0 0
The SQL Query I am using is this:
select * from
(select clients.ClientID, clients.serviceID FROM clients left join visits on visit.cliendid=clients.clientid ) e
pivot ( COUNT(serviceID) for serviceID in ([1],[2],...,[54]) ) p
But this SQL Query doesn't do what I want, instead it does this:
ID [1] [2] [3] [4] [5]
1 0 4 0 0 2
2 1 0 0 0 0
3 0 2 1 0 0
I need all of the data in the columns to be either 0 or 1, as in, 0 has never used this service, 1 has used this service...
How do I do this?
It would be awesome if I could do pivot ( Math.MIN ( COUNT(serviceID), 0 ) for ... or if I could do ( CASE (COUNT(serviceID) > 0 ) THEN 1 ELSE 0 for ...
but it won't let me.

SELECT *
FROM (
SELECT DISTINCT clients.ClientID, clients.serviceID
FROM clients
) e
PIVOT (
COUNT(serviceID)
FOR serviceID in ([1],[2])
) p

Related

Use Sum on extra aggregation and Make Total

I want to create an indexed View.
I have this query:
SELECT srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
SUM( IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0)) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum,
COUNT_BIG(*) AS CountLines
FROM table1 srvmn
JOIN table2 srv
ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv
ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321
AND srv.State <> 123
GROUP BY srvInv.ObjectID,
srv.State,
srvInv.Direction,
srvInv.ReverseBroken,
srvmn.BBC_ID
ORDER BY srvInv.ObjectID
So, the Sum is not working properly also I fix it with this approach:
SELECT A.Inventory,
A.ObjectID,
A.State,
A.Broken,
SUM(A.Sum) AS Sum
FROM
(
SELECT srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum,
COUNT_BIG(*) AS CountLines
FROM table1 srvmn
JOIN table2 srv
ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv
ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321
AND srv.State <> 123
GROUP BY srvInv.ObjectID,
srv.State,
srvInv.Direction,
srvInv.ReverseBroken,
srvmn.BBC_ID
) AS A
GROUP BY A.Inventory,
A.ObjectID,
A.State,
A.Broken;
Result is OK, but Derived Tables are not allowed in Indexed Views.
I try to using "Over Partition" in Sum, but the result is not OK.
How I can fix this issue?
Correct Result :
Inventory ObjectID State Broken Sum
------------------------------------------------
NULL 2 500 0 -1
NULL 3 320 1 1
NULL 3 500 0 2
NULL 3 600 0 1
NULL 18 600 0 -1
NULL 20 600 0 -1
1162 20 600 0 1
NULL 24 600 0 1
NULL 26 310 0 -3
NULL 26 320 0 -1
NULL 26 600 0 7
442 26 500 0 8
442 26 500 1 1
442 26 600 0 -5
1162 26 600 0 0
NULL 27 500 0 4
NULL 27 600 0 2
1162 27 600 0 1
1162 28 600 0 3
Not Ok Result:
Inventory ObjectID State Broken Sum CountLines
-------------------------------------------------------------
NULL 2 500 0 -1 1
NULL 3 500 0 2 2
NULL 3 600 0 1 1
NULL 18 600 0 -1 1
1162 20 600 0 3 3
1162 20 600 0 -2 2
NULL 20 600 0 1 1
NULL 20 600 0 -2 2
NULL 24 600 0 -1 1
NULL 24 600 0 2 2
442 26 600 0 -7 7
NULL 26 600 0 -18 18
1162 26 600 0 1 1
NULL 26 600 0 25 25
442 26 500 1 1 1
442 26 600 0 2 2
1162 26 600 0 -1 1
442 26 500 0 8 8
NULL 27 600 0 -3 3
1162 27 600 0 1 1
Please try it :
SELECT
srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
SUM(IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0)) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum
FROM table1 srvmn
JOIN table2 srv ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321 AND srv.State <> 123
GROUP BY
srvInv.ObjectID,
srv.State,
srvInv.ReverseBroken,
srvmn.BBC_ID
You should not use Field "srvInv.Direction" in "Group By"

SQL Pivot Table - Subqueries

I have a program that is logging the time a user spends on certain aspects, some are identified as specific "time". I'm struggling to get multiple lines of Grouped query results into a single line for each month as a "summary".
My current query:
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC
FROM User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
Current results:
TotalMins DateMonth ID1 PC1
192 1 0 0
306 1 0 100
113 2 0 0
365 2 0 100
14 2 1 0
3 2 1 100
75 3 0 0
253 3 0 100
3 3 1 0
300 4 0 0
233 4 0 100
10 4 1 0
23 4 1 100
438 5 0 0
134 5 0 100
19 5 1 0
49 5 1 100
0 9 1 0
11 10 0 0
21 10 0 60
167 10 1 100
What I would like to do from this point is to create a table showing all 12 months, regardless of whether there is information within that month or not, and show the relative information within each row for that month. for example:
DateMonth NonID1 TimeID1 TimePC1 (Round((PC1/100)*TotalMins)) TimePC1ID1
1 192 0 306 0
2 113 14 365 3
3 75 3 253 0
4 300 10 233 23
5 438 19 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 11 0 13 167
11 0 0 0 0
12 0 0 0 0
What's the most efficient way to do this?
Note: I have also created a table to give me 1-12 as rows that I can use to give me the months that I need to use, where information is not within the user_time_log.
Here's a simple way to do what you're looking for:
First, create your table of month values. I made a simple temp table with a single column.
CREATE TABLE #Dates (MonthNum INT)
INSERT INTO #Dates
(
MonthNum
)
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
Next, you can put your existing query into a CTE, then LEFT JOIN to your table of months. You'll want to put your columns into a SUM'd CASE statement, like so:
;WITH Aggregation AS
(
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC1
FROM #User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
)
SELECT
d.MonthNum
,NonID1 = SUM(CASE WHEN ID1 = 0 THEN TotalMins ELSE 0 END)
,TimeID1 = SUM(CASE WHEN ID1 = 1 THEN TotalMins ELSE 0 END)
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
FROM #Dates d
LEFT JOIN Aggregation a ON d.MonthNum = a.DateMonth
GROUP BY d.MonthNum
Output would then look like this:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306 0
2 478 17 365 3
3 328 3 253 0
4 533 33 233 23
5 572 68 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 32 167 0 167
11 0 0 0 0
12 0 0 0 0
EDIT:
The ROUND() function call can be changed slightly to accomodate your need for decimal results. The first parameter of ROUND() is the expression you want to round, and the second is the number of decimal places to round to. Positive numbers indicate the number of places to the right of the decimal to round to. Negative numbers indicate the number of places to the left of the decimal to round to. So if you set it to 2, you'll get an answer rounded to the nearest hundredth.
But there's one more tweak we need. PC1 and TotalMins are both assumed to be INTs in my answer. So we have to give the SQL engine a little help so that it calculates the answer as a DECIMAL. By CAST()ing the INTs to DECIMALs, SQL will perform the arithmetic op as decimal math instead of integer math. You'd just have to change TimePC1 and TimePC1ID1 like so:
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
Then the output looks like this:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306.000000 0.000000
2 478 17 365.000000 3.000000
3 328 3 253.000000 0.000000
4 533 33 233.000000 23.000000
5 572 68 134.000000 49.000000
6 0 0 0.000000 0.000000
7 0 0 0.000000 0.000000
8 0 0 0.000000 0.000000
9 0 0 0.000000 0.000000
10 32 167 12.600000 167.000000
11 0 0 0.000000 0.000000
12 0 0 0.000000 0.000000

SQL Server tabulating survey data for every month

I have a survey table with many columns but i am focusing on these 2, survey_date and over_rating. i am not sure if it is possible to be done in a single query. I am using sql server 2012. This is my sample data.
select survey_date, overall_rating from survey
survey_date overall_rating
2017-01-06 15:09:51.940 6
2017-02-06 14:18:18.620 4
2017-05-07 16:03:12.037 7
2017-05-23 10:41:30.357 7
2017-05-23 10:41:30.357 5
2017-05-24 12:05:25.217 8
2017-06-01 09:03:47.727 7
2017-06-05 09:01:07.283 9
2017-06-05 09:28:12.597 6
2017-06-15 09:47:29.407 7
2017-07-06 12:10:50.003 2
2017-07-06 13:45:52.997 7
2017-08-06 14:00:35.403 5
2017-08-09 12:21:17.367 8
I need to count the occurrence for each rating 1-10, for each month, and sum it up. Example June 15, rating 10 have 1, rating 9 have 10, ...
This is the result table:
Month 10 9 8 7 6 5 4 3 2 1 Avg Score Total Total >=6 CSI
June'15 1 10 20 3 0 0 0 0 0 0 8 34 34 100%
July'15 1 16 14 0 0 0 0 0 1 0 9 32 31 99%
August'15 7 6 6 0 0 0 0 0 0 0 9 19 19 100%
September'15 0 2 2 0 0 0 0 0 0 0 9 4 4 100%
November'15 0 1 2 0 0 0 0 0 0 0 8 3 3 100%
December'15 0 7 3 4 2 0 0 0 0 0 8 16 16 100%
i have tried this query but is partly wrong as there is duplicate month for each rating:
select si.yr, si.mn,
case when si.overall_rating = 10 then count(si.overall_rating) else 0 end as '10',
case when si.overall_rating = 9 then count(si.overall_rating) else 0 end as '9',
case when si.overall_rating = 8 then count(si.overall_rating) else 0 end as '8',
case when si.overall_rating = 7 then count(si.overall_rating) else 0 end as '7',
case when si.overall_rating = 6 then count(si.overall_rating) else 0 end as '6',
case when si.overall_rating = 5 then count(si.overall_rating) else 0 end as '5',
case when si.overall_rating = 4 then count(si.overall_rating) else 0 end as '4',
case when si.overall_rating = 3 then count(si.overall_rating) else 0 end as '3',
case when si.overall_rating = 2 then count(si.overall_rating) else 0 end as '2',
case when si.overall_rating = 1 then count(si.overall_rating) else 0 end as '1',
sum(si.overall_rating) as month_count
from
(select YEAR(s.survey_date) yr, MONTH(s.survey_date) mn, s.overall_rating
from survey s where s.status='Submitted' and s.survey_date >= '2017-01-01' AND s.survey_date <= '2017-12-31'
group by YEAR(s.survey_date), MONTH(s.survey_date), s.overall_rating) si group by si.yr, si.mn, si.overall_rating;
Results:
yr mm 10 9 8 7 6 5 4 3 2 1 total
2017 1 0 0 0 0 1 0 0 0 0 0 6
2017 2 0 0 0 0 0 0 1 0 0 0 4
2017 5 0 0 0 0 0 1 0 0 0 0 5
2017 5 0 0 0 1 0 0 0 0 0 0 7
2017 5 0 0 1 0 0 0 0 0 0 0 8
2017 6 0 0 0 0 1 0 0 0 0 0 6
2017 6 0 0 0 1 0 0 0 0 0 0 7
2017 6 0 1 0 0 0 0 0 0 0 0 9
2017 7 0 0 0 0 0 0 0 0 1 0 2
2017 7 0 0 0 1 0 0 0 0 0 0 7
2017 8 0 0 0 0 0 1 0 0 0 0 5
2017 8 0 0 1 0 0 0 0 0 0 0 8
As you can see 5 and 6 are repeated for different rating. If anyone could tell me is it possible to be done in a single query. Thanks
I think I understand what you are trying to achieve here and you'll be pleased to know you are not far off. You have the right idea in using a conditional aggregate, but you need to wrap your conditional case expression in the aggregate, not the other way around. To do a conditional count, you can simply return 1 for a condition match and 0 for a no match and then sum up the result.
Doing this allows your group by to remain nice and simple:
declare #t table(survey_date datetime,overall_rating int);
insert into #t values ('2017-01-06 15:09:51.940',6),('2017-02-06 14:18:18.620',4),('2017-05-07 16:03:12.037',7),('2017-05-23 10:41:30.357',7),('2017-05-23 10:41:30.357',5),('2017-05-24 12:05:25.217',8),('2017-06-01 09:03:47.727',7),('2017-06-05 09:01:07.283',9),('2017-06-05 09:28:12.597',6),('2017-06-15 09:47:29.407',7),('2017-07-06 12:10:50.003',2),('2017-07-06 13:45:52.997',7),('2017-08-06 14:00:35.403',5),('2017-08-09 12:21:17.367',8);
select dateadd(m,datediff(m,0,survey_date),0) as [Month]
,sum(case when overall_rating = 10 then 1 else 0 end) as [10]
,sum(case when overall_rating = 9 then 1 else 0 end) as [9]
,sum(case when overall_rating = 8 then 1 else 0 end) as [8]
,sum(case when overall_rating = 7 then 1 else 0 end) as [7]
,sum(case when overall_rating = 6 then 1 else 0 end) as [6]
,sum(case when overall_rating = 5 then 1 else 0 end) as [5]
,sum(case when overall_rating = 4 then 1 else 0 end) as [4]
,sum(case when overall_rating = 3 then 1 else 0 end) as [3]
,sum(case when overall_rating = 2 then 1 else 0 end) as [2]
,sum(case when overall_rating = 1 then 1 else 0 end) as [1]
,count(overall_rating) as ScoresReturned
,sum(overall_rating) as TotalScore
,avg(cast(overall_rating as decimal(10,0))) as Average
from #t
group by dateadd(m,datediff(m,0,survey_date),0)
order by [Month];
Output:
+-------------------------+----+---+---+---+---+---+---+---+---+---+----------------+------------+----------+
| Month | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | ScoresReturned | TotalScore | Average |
+-------------------------+----+---+---+---+---+---+---+---+---+---+----------------+------------+----------+
| 2017-01-01 00:00:00.000 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 6 | 6.000000 |
| 2017-02-01 00:00:00.000 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 4 | 4.000000 |
| 2017-05-01 00:00:00.000 | 0 | 0 | 1 | 2 | 0 | 1 | 0 | 0 | 0 | 0 | 4 | 27 | 6.750000 |
| 2017-06-01 00:00:00.000 | 0 | 1 | 0 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 4 | 29 | 7.250000 |
| 2017-07-01 00:00:00.000 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 2 | 9 | 4.500000 |
| 2017-08-01 00:00:00.000 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 2 | 13 | 6.500000 |
+-------------------------+----+---+---+---+---+---+---+---+---+---+----------------+------------+----------+
select si.yr, si.mn,
case when si.overall_rating = 10 then count(si.overall_rating) else 0 end as '10',
case when si.overall_rating = 9 then count(si.overall_rating) else 0 end as '9',
case when si.overall_rating = 8 then count(si.overall_rating) else 0 end as '8',
case when si.overall_rating = 7 then count(si.overall_rating) else 0 end as '7',
case when si.overall_rating = 6 then count(si.overall_rating) else 0 end as '6',
case when si.overall_rating = 5 then count(si.overall_rating) else 0 end as '5',
case when si.overall_rating = 4 then count(si.overall_rating) else 0 end as '4',
case when si.overall_rating = 3 then count(si.overall_rating) else 0 end as '3',
case when si.overall_rating = 2 then count(si.overall_rating) else 0 end as '2',
case when si.overall_rating = 1 then count(si.overall_rating) else 0 end as '1',
sum(si.overall_rating) as month_count
from
(select YEAR(s.survey_date) yr, MONTH(s.survey_date) mn, s.overall_rating
from survey s where s.status='Submitted' and s.survey_date >= '2017-01-01' AND s.survey_date <= '2017-12-31'
group by YEAR(s.survey_date), MONTH(s.survey_date), s.overall_rating) si group by si.yr, si.mn;
You must remove si.overall_rating in Group By
Oh! I posted late, anyway you can try this otherwise.
DATA:
IF ( OBJECT_ID('tempdb..#temptable') IS NOT NULL )
BEGIN
DROP TABLE #temptable
END
CREATE TABLE #temptable
(
survey_date DATETIME ,
overall_rating NUMERIC(22,2)
)
INSERT INTO #temptable
( survey_date, overall_rating )
VALUES ( '2017-01-06 15:09:51.940', 6 ),
( '2017-02-06 14:18:18.620', 4 ),
( '2017-05-07 16:03:12.037', 7 ),
( '2017-05-23 10:41:30.357', 7 ),
( '2017-05-23 10:41:30.357', 5 ),
( '2017-05-24 12:05:25.217', 8 ),
( '2017-06-01 09:03:47.727', 7 ),
( '2017-06-05 09:01:07.283', 9 ),
( '2017-06-05 09:28:12.597', 6 ),
( '2017-06-15 09:47:29.407', 7 ),
( '2017-07-06 12:10:50.003', 2 ),
( '2017-07-06 13:45:52.997', 7 ),
( '2017-08-06 14:00:35.403', 5 ),
( '2017-08-09 12:21:17.367', 8 )
QUERY:
;
WITH CTE
AS ( SELECT DATENAME(month, survey_date) + ' '''
+ RIGHT(CAST(YEAR(survey_date) AS NVARCHAR(4)),
2) AS [Month] ,
ISNULL([1], 0) [1] ,
ISNULL([2], 0) [2] ,
ISNULL([3], 0) [3] ,
ISNULL([4], 0) [4] ,
ISNULL([5], 0) [5] ,
ISNULL([6], 0) [6] ,
ISNULL([7], 0) [7] ,
ISNULL([8], 0) [8] ,
ISNULL([9], 0) [9] ,
ISNULL([10], 0) [10],
Total,
Average
FROM ( SELECT survey_date ,
COUNT(overall_rating) overall_rating,
CAST(SUM(overall_rating) AS INT) Total,
AVG(overall_rating) Average
FROM ( SELECT DATEADD(MONTH,
DATEDIFF(MONTH,
0, survey_date),
0) survey_date ,
overall_rating
FROM #temptable
) T
GROUP BY t.survey_date
) PVT PIVOT ( SUM(overall_rating) FOR overall_rating IN ( [1],
[2], [3], [4],
[5], [6], [7],
[8], [9], [10] ) ) P
)
SELECT [Month] ,
ISNULL([1], 0) [1] ,
ISNULL([2], 0) [2] ,
ISNULL([3], 0) [3] ,
ISNULL([4], 0) [4] ,
ISNULL([5], 0) [5] ,
ISNULL([6], 0) [6] ,
ISNULL([7], 0) [7] ,
ISNULL([8], 0) [8] ,
ISNULL([9], 0) [9] ,
ISNULL([10], 0) [10],
Total,
Average
FROM CTE
RESULT:
Month 1 2 3 4 5 6 7 8 9 10 Total Average
----------------------- ------ ---- ----- ----- ----- ----- ---- ---- ----- ----- ----------- -------------
January '17 1 0 0 0 0 0 0 0 0 0 6 6.000000
February '17 1 0 0 0 0 0 0 0 0 0 4 4.000000
May '17 0 0 0 4 0 0 0 0 0 0 27 6.750000
June '17 0 0 0 4 0 0 0 0 0 0 29 7.250000
July '17 0 2 0 0 0 0 0 0 0 0 9 4.500000
August '17 0 2 0 0 0 0 0 0 0 0 13 6.500000
(6 row(s) affected)

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;

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