Count columns with a value x at least once - sql-server

Suppose I have this table:
A B C
------------
1 0 0
0 0 1
1 0 1
0 0 0
I need the count of columns where 1 occurs (irrespective of the number of times it occurs). So in this example the count would be 2 since it occurs in 2 columns A & C.
How can this be done in SQL server?
Edit: From comments
Number of columns maybe fixed but unknown

A query like below will give you correct results if number of columns are known, for unknown number of columns this query can be made dynamic.
SELECT
MAX(CASE WHEN colA = 1 THEN 1 ELSE 0 END) +
MAX(CASE WHEN colB = 1 THEN 1 ELSE 0 END) +
MAX(CASE WHEN colC = 1 THEN 1 ELSE 0 END) +
--...
MAX(CASE WHEN colZ = 1 THEN 1 ELSE 0 END) as CountOfColumns
FROM tableT
Below is a dynamic query:
declare #q varchar(max)
select
#q= 'select ' +
stuff((
select
'+ MAX(CASE WHEN ' + C.name + ' = 1 THEN 1 ELSE 0 END) '
from
sys.columns C inner join sys.tables T
on C.object_id=T.object_id and T.name='tableT'
for xml path('')),1,1,'')
+ ' as CountOfColumns FROM tableT'
exec( #q)

Related

SQL Server : create a table where the columns are a row - index mod x

I have a table containing 2 columns - identifier (1, 2, 3...) and the value.
It is necessary to make a table, where as columns will be the remnants of division of identifiers by 3.
An example:
Table1:
id value
----------
1 aaa
2 bbb
3 ccc
4 ddd
5 eee
6 fff
Result should be:
0 1 2
----------------
aaa bbb ccc
ddd eee fff
Tell me please how to do it in SQL Server.
PS. whether it is possible to realize it not using an identifier as a separate column, but using only the actual row number
You can do conditional aggregation. If id starts at 1 and is always incrementing, without gaps, then:
select
max(case when (id - 1) % 3 = 0 then value end) value1,
max(case when (id - 1) % 3 = 1 then value end) value2,
max(case when (id - 1) % 3 = 2 then value end) value3
from from mytable t
group by (id - 1) / 3
Otherwise we can generate a sequence with row_number():
select
max(case when rn % 3 = 0 then value end) value1,
max(case when rn % 3 = 1 then value end) value2,
max(case when rn % 3 = 2 then value end) value3
from (
select t.*, row_number() over(order by id) - 1 rn
from mytable t
) t
group by rn / 3
Late answer, but here is an option that you can dynamically define the number of columns
Example
Declare #Col int = 3
Declare #SQL varchar(max) = stuff( ( Select ',' + QuoteName([N])
From ( Select Top (#Col) N=-1+Row_Number() Over (Order By (Select NULL))
From master..spt_values
) n1
For XML Path('')),1,1,'')
Set #SQL = '
Declare #Col int = '+convert(varchar(10),#Col)+';
Select '+#SQL+'
From (
Select Value
,ColNr=(row_number() over (order by id) - 1) % #Col
,RowNr=(row_number() over (order by id) - 1) / #Col
From #YourTable
) src
Pivot ( max(Value) for ColNr in ('+#SQL+' ) ) pvt '
Exec(#SQL)
Returns
0 1 2
aaa bbb ccc
ddd eee fff

How to Mentioned Leavetype in employee attendance register?

I have two tables. One is employee attendance and second one is Employee Leave.
Employee attendance col( Empid,INTIME,OUTTIME,Status)
Employee Leave col(Empid,StartDate,Endate,leavetype(PL,CL,SL))
I have created pivot table in which present, absent and HD mentioned and created another separate query for sum of row (Present ,absent and HD) From EmployeeAttendance Table.
===Sum query===
SELECT SUM(CASE WHEN status = 'P' THEN 1
WHEN status = 'HD' THEN 0.5 WHEN status = 'A' THEN 0 END) AS [T.P],
SUM(CASE WHEN status = 'A' THEN 1 WHEN status = 'HD' THEN 0.5 END) AS [A],
SUM(CASE WHEN status = 'P' THEN 1
WHEN status = 'HD' THEN 1 WHEN status = 'A' THEN 1 END) AS [TDay ]
FROM EmployeesAttendance
--WHERE (ReportingDate BETWEEN #StartDate AND #Enddate)
GROUP BY EmpID
===Pivot Table ===
for converting col into row
SELECT DISTINCT ReportingDate INTO #Dates
FROM EmployeesAttendance
ORDER BY ReportingDate
DECLARE #cols NVARCHAR(4000)
SELECT #cols = COALESCE(#cols + ',[' + CONVERT(varchar, DATEPART(DAY, ReportingDate), 112)
+ ']','[' + CONVERT(varchar,DATEPART(DAY, ReportingDate), 112) + ']')
FROM #Dates
ORDER BY ReportingDate
DECLARE #qry NVARCHAR(4000) =
N'SELECT *
FROM (SElECT EmployeeDetails.EmpID,EmployeeDetails.EmpName,EmployeesAttendance.Status,
DATEPART(DAY, EmployeesAttendance.ReportingDate)as DDate
FROM EmployeesAttendance Inner Join EmployeeDetails on EmployeesAttendance.EmpID=EmployeeDetails.Empid )
emp
PIVOT (MAX(Status) FOR DDate IN (' + #cols + ')) AS stat
-- Executing the query
EXEC(#qry)
I want this Employee attendance Register.
Date 1 2 3 4 5 Total Absent Present Leave
Emp1 P P A PL P 5 1 3 1
Emp2 Cl pl A PL P 5 1 2 2
Now I want to merge above bother query of Sum and Pivot, also mentioned leave type in attendance register if employee availed leaves From 01-01-2019 to 02-01-2019 Noofdays equal to 2 for (emp2)

Long to wide - SQL [duplicate]

This question already has answers here:
SQL Server dynamic PIVOT query?
(9 answers)
Closed 6 years ago.
I have a table that is long (for example)
Date Person Number
2015-01-03 A 4
2015-01-04 A 2
2015-01-05 A 3
2015-01-03 B 5
2015-01-04 B 6
2015-01-05 B 7
2015-01-03 C 1
2015-01-04 C 3
2015-01-05 C 4
2015-01-05 D 4
2015-01-04 E 1
2015-01-05 E 3
And I need it to look like (wide):
Date A B C D E
2015-01-03 4 5 1 0 0
2015-01-04 2 6 3 0 1
2015-01-05 3 7 4 4 3
Any help would be much appreciated. I am using Transact. Thanks.
Using PIVOT:
select date, isNull([A], 0) as A,
isNull([B], 0) as B,
isNull([C], 0) as C,
isNull([D], 0) as D,
isNull([E], 0) as E
from
( select date, person, number
from tbl ) AS SourceTable
PIVOT
( max(number) for
Person in ( [A], [B], [C], [D], [E]) ) AS PivotTable;
Dynamic version is:
DECLARE #columns NVARCHAR(MAX), #whereColumns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SET #whereColumns = N'';
SELECT #columns += N', isNull(p.' + QUOTENAME(Person) +', 0) as ' + Person,
#whereColumns += N', ' +QUOTENAME (Person)
FROM (select Person from tbl group by Person) AS x;
SET #sql = N'
select date, ' + STUFF(#columns, 1, 2, '') +
N'
from
( select date, person, number
from tbl ) AS SourceTable
PIVOT
( max(number) for
Person in ( '
+ stuff(#whereColumns, 1, 2, '')
+ ' )
) AS P '
print #sql;
exec (#sql);
You can use conditional aggregation:
SELECT
Date,
[A] = MAX(CASE WHEN Person = 'A' THEN Number ELSE 0 END),
[B] = MAX(CASE WHEN Person = 'B' THEN Number ELSE 0 END),
[C] = MAX(CASE WHEN Person = 'C' THEN Number ELSE 0 END),
[D] = MAX(CASE WHEN Person = 'D' THEN Number ELSE 0 END),
[E] = MAX(CASE WHEN Person = 'E' THEN Number ELSE 0 END)
FROM #tbl
GROUP BY Date
If you have unknown number of Persons, then you have to do it dynamically:
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
Date' + CHAR(10) +
(
SELECT DISTINCT
' , MAX(CASE WHEN Person = ''' + Person + ''' THEN Number ELSE 0 END) AS ' + QUOTENAME(Person) + CHAR(10)
FROM #tbl
FOR XML PATH('')
) +
'FROM #tbl
GROUP BY Date;';
PRINT (#sql);
EXEC (#sql);
ONLINE DEMO

join multiple queries result in to seperate columns

hello everyone i have 3 queries it gives when i used union All its give me 3 rows i want to convert 3 rows into columns how can i do that please help me
here is my query
( select count(*) As TotalCount from Detail_User
where userkey = 172 )
--union
( select count(*) As ICount1 from Detail_User
where Parent_Name = 'A' and userkey = 172 )
--union
( select count(*) As ICount2 from Detail_User
where Parent_Name = 'B' and userkey = 172 )
its give me some thing like this
TotalCount
2
3
5
i want something like this
TotalCount ICount1 ICount2
2 3 5
Don't do a UNION, use a CASE WHEN in your SELECT like this
select
count(*) As TotalCount,
SUM(CASE WHEN Parent_Name = 'A' THEN 1 ELSE 0 END) as ICount1 ,
SUM(CASE WHEN Parent_Name = 'B' THEN 1 ELSE 0 END) as ICount2
from Detail_User
where userkey = 172

Group By dynamic list with Count

I'm using a simple case statement to count the occurrences of breakcode in my data and grouping by Seller and SaleDate.
However it seems like an inelegant solution. The breakcode could and quite possibly will expand and I would need to update my code when it does. How can this be done?
Additionally, while using NULL gives me the right answers, I would like to know is there a better approach to how I am counting my instances of breakcode, putting 0 in place of NULL returns the incorrect results?
SELECT seller,
saledate,
COUNT(CASE WHEN breakcode = 1 then 1 ELSE NULL END) as [Perfect],
COUNT(CASE WHEN breakcode = 2 then 1 ELSE NULL END) as [Simple],
COUNT(CASE WHEN breakcode = 3 then 1 ELSE NULL END) as [Medium],
COUNT(CASE WHEN breakcode = 4 then 1 ELSE NULL END) as [Dual1],
COUNT(CASE WHEN breakcode = 5 then 1 ELSE NULL END) as [Dual2],
COUNT(CASE WHEN breakcode = 6 then 1 ELSE NULL END) as [Hard],
COUNT(CASE WHEN breakcode = 7 then 1 ELSE NULL END) as [Difficult]
FROM test
GROUP BY seller, sale date
Thanks.
SQLFiddle: http://sqlfiddle.com/#!3/26f6d/2
Final version developed through comments:
DECLARE #sql AS NVARCHAR(MAX)
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols= ISNULL(#cols + ',','') + QUOTENAME(case when breakname like 'Perfect%' then 'Perfect' else breakname end)
FROM (select * from breaks where breakname not like 'Perfect - 90') a
group by id, breakname
order by id
SET #sql =
N'SELECT seller, saledate, ' + #cols + '
FROM (select seller, saledate, case when breakname like ''Perfect%'' then ''Perfect'' else breakname end breakname from test
inner join breaks on case when breakcode = 8 then 1 else breakcode end = id) derived
PIVOT(count(breakname)
FOR derived.breakname IN (' + #cols + ')) AS PVTTable
ORDER BY seller, saledate'
EXEC sp_executesql #sql
SQL Fiddle

Resources