TSQL - SQL 2000 - sql-server

I'm struggling with this one. I have a table A which looks like this:
Employee_ID Dependant_FirstName DOB
1 John 12/12/1980
1 Lisa 11/11/1982
2 Mark 06/06/1985
2 Shane 07/07/1982
2 Mike 03/04/1990
3 NULL NULL
and would like to copy these data in Table B like this (knowing that there could only be a maximum of 6 dependants in Table A):
Employee_ID Dependant1_FirstName DOB Dependant2_FirstName DOB Dependant3_FirstName DOB
1 John 12/12/1980 Lisa 11/11/1982 NULL NULL
2 Mark 06/06/1985 Shane 07/07/1982 Mike 03/04/1990
3 NULL NULL NULL NULL NULL NULL
Thanks very much for the help.
Marc

This is a working example for just your example data, to give an idea of how I'd do it. I'm using a faked-up dependant counter based on date of birth and name. Bear in mind it will break if an employee has twins with the same name, but if they do that, then they deserve all the lifelong data-confusion that they've got in store :)
Also, please consider upgrading that SQL Server. Or moving this kind of pivoting to your reporting tool rather than the database.
CREATE TABLE #employees (employee_id INTEGER, Dependant_FirstName VARCHAR(20), DOB DATETIME)
INSERT INTO #employees VALUES (1, 'John', '12/12/1980')
INSERT INTO #employees VALUES (1, 'Lisa', '11/11/1982')
INSERT INTO #employees VALUES (2, 'Shane', '07/07/1982')
INSERT INTO #employees VALUES (2, 'Mark', '06/06/1985')
INSERT INTO #employees VALUES (2, 'Mike', '03/04/1990')
INSERT INTO #employees VALUES (3, NULL, NULL)
SELECT
employee_id,
MAX(CASE WHEN dep_count = 1 THEN Dependant_FirstName ELSE NULL END) 'Dependant1_FirstName',
MAX(CASE WHEN dep_count = 1 THEN DOB ELSE NULL END) 'Dependant1_DOB',
MAX(CASE WHEN dep_count = 2 THEN Dependant_FirstName ELSE NULL END) 'Dependant2_FirstName',
MAX(CASE WHEN dep_count = 2 THEN DOB ELSE NULL END) 'Dependant2_DOB',
MAX(CASE WHEN dep_count = 3 THEN Dependant_FirstName ELSE NULL END) 'Dependant3_FirstName',
MAX(CASE WHEN dep_count = 3 THEN DOB ELSE NULL END) 'Dependant3_DOB'
FROM
(
SELECT
employee_id,
Dependant_FirstName,
DOB,
(
SELECT
COUNT(*)
FROM
#employees deps
WHERE
#employees.employee_id = deps.employee_id AND
CONVERT(VARCHAR, #employees.DOB, 126) + #employees.Dependant_FirstName <=
CONVERT(VARCHAR, deps.DOB, 126) + deps.Dependant_FirstName
) 'dep_count'
FROM
#employees
) add_dep_count_query
GROUP BY
employee_id

You could
Create a view
Calculate a fictuous ranking
Group to find the maximum ranking for each employee_ID
return the results.
Note: I have ommitted the DOB column in the examples
Statement
CREATE VIEW dbo.VIEW_Employees_Ranking AS
SELECT Ranking = ISNULL(e6.Employee_ID, 0)
+ ISNULL(e5.Employee_ID, 0)
+ ISNULL(e4.Employee_ID, 0)
+ ISNULL(e3.Employee_ID, 0)
+ ISNULL(e2.Employee_ID, 0)
+ ISNULL(e1.Employee_ID, 0)
, e1.Employee_ID
, Name1 = e1.Dependant_FirstName
, Name2 = e2.Dependant_FirstName
, Name3 = e3.Dependant_FirstName
, Name4 = e4.Dependant_FirstName
, Name5 = e5.Dependant_FirstName
, Name6 = e6.Dependant_FirstName
FROM dbo.Employees e1
LEFT OUTER JOIN dbo.Employees e2 ON e2.Employee_ID = e1.Employee_ID AND e2.DOB > e1.DOB
LEFT OUTER JOIN dbo.Employees e3 ON e3.Employee_ID = e2.Employee_ID AND e3.DOB > e2.DOB
LEFT OUTER JOIN dbo.Employees e4 ON e4.Employee_ID = e3.Employee_ID AND e4.DOB > e3.DOB
LEFT OUTER JOIN dbo.Employees e5 ON e5.Employee_ID = e4.Employee_ID AND e5.DOB > e4.DOB
LEFT OUTER JOIN dbo.Employees e6 ON e6.Employee_ID = e5.Employee_ID AND e6.DOB > e5.DOB
GO
SELECT er.*
FROM dbo.VIEW_Employees_Ranking er
INNER JOIN (
SELECT Ranking = MAX(Ranking)
, Employee_ID
FROM dbo.VIEW_Employees_Ranking
GROUP BY
Employee_ID
) ermax ON ermax.Ranking = er.Ranking AND ermax.Employee_ID = er.Employee_ID

Check this code please, It might work for you.
declare #Emp_Id int
declare #Name int
declare #DOB int
declare #Count int
set #Count=1
DECLARE x_cursor CURSOR FOR
SELECT distinct Employee_ID from tableA
OPEN x_cursor
FETCH NEXT FROM x_cursor
INTO #Emp_Id
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE second_cursor CURSOR FOR
SELECT distinct Dependant_FirstName,DOB from tableA
where Employee_ID=#Emp_Id
OPEN second_cursor
FETCH NEXT FROM second_cursor
INTO #Name,#DOB
WHILE ##FETCH_STATUS = 0
BEGIN
if(#Count=1)
begin
insert into tableB (Employee_ID , Dependant1_FirstName,DOB)
values(#Emp_Id,#Name,#DOB)
set #Count=#Count+1
end
else
begin
exec('Update tableB set Dependant'+#count+'_FirstName='+#Name+' ,DOB'+#Count+'='+#DOB+' where Employee_ID='+#Emp_Id)
set #Count=#Count+1
end
FETCH NEXT FROM second_cursor
INTO #Name,#DOB
END
CLOSE second_cursor
DEALLOCATE second_cursor
set #Count=1
FETCH NEXT FROM x_cursor
INTO #Emp_Id
END
CLOSE x_cursor;
DEALLOCATE x_cursor
GO

Have a look at this example:
http://ryanfarley.com/blog/archive/2005/02/17/1712.aspx
here he is concatentating the child elements of a parent key into a string which should allow you to write out a flat record.

Related

SQL Server : CONCAT with CASE

I have been playing a lot with this and am failing to get the answers.
Query CASES:
If there is EndDate in Table1 and no EndDate in Table 2, then concatenate Table1 SSC + Table1 StartDate + Table1 EndDate
If there is no EndDate on both tables then display Table1 SSC value + Table2 StartDate space value from Table2 Data column
Sample of tables
CREATE TABLE temp.dbo.Table1
(
CID INT,
PID INT,
SSC VARCHAR(3),
StartDate VARCHAR(20),
EndDate VARCHAR(20),
Data VARCHAR(20)
)
INSERT INTO temp.dbo.Table1
VALUES
(1001, 1333, 'OP','20011505','19952012','OP2001156519952012'),
(1002, 1245, 'OR','20121005',NULL,'OR20121005'),
(1003, 1116, 'OP','20131215',NULL,'OP20131215'),
(1004, 1234, 'OP','20011505','19952012','OP2001156519952012')
CREATE TABLE temp.dbo.Table2
(
CID INT,
PID INT,
SSC VARCHAR(3),
StartDate VARCHAR(20),
EndDate VARCHAR(20),
Data VARCHAR(20)
)
INSERT INTO temp.dbo.Table2
VALUES
(1001, 1333, 'OP','20111015',NULL,'OP20111015'),
(1002, 1245, 'OR','20131005',NULL,'OR20131005'),
(1003, 1116, 'OP','20131415',NULL,'OP2013141520131516'),
(1004, 1235, 'OP','20121015',NULL,'OP20121015')
My query which I am working on is here
SELECT
T1.CID,
T1.PID,
CASE
WHEN T1.EndDate IS NOT NULL AND ISNULL(T2.EndDate,'') <>''
THEN CONCAT(T1.SSC, T1.StartDate, T1.EndDate)
WHEN ISNULL(T1.EndDate,'') <> '' AND ISNULL(T2.EndDate,'') <> ''
THEN CONCAT(T1.SSC, T2.StartDate, ' ', T2.Data)
ELSE NULL
END
FROM
temp.dbo.TABLE1 AS T1
LEFT JOIN
temp.dbo.TABLE2 AS T2 ON T1.CID = T2.CID AND T1.PID = T2.PID AND T1.SSC = T2.SSC
This screenshot shows sample data:
You were close, just a small syntax error.
Your first scenario:
Query CASES: 1_If there is EndDate in Table1 and no EndDate in Table 2, then concatenate Table1 SSC + Table1 StartDate + Table1 EndDate IF you look at your case statement isnull(t2.enddate,'') should be = '' rather than <> ''
2_If there is no EndDate on both tables then display Table1 SSC value + Table2 StartDate space value from Table2 Data column
For second case statement it should be (isnull = rather than <> for both of them
This query will give your desired output.
SELECT T1.CID
,T1.PID
,CASE
WHEN T1.EndDate IS NOT NULL AND ISNULL(T2.EndDate,'') = '' THEN CONCAT(T1.SSC, T1.StartDate,T1.EndDate)
WHEN ISNULL(T1.EndDate,'') = '' AND ISNULL(T2.EndDate,'') = '' THEN CONCAT(T1.SSC, T2.StartDate, ' ', T2.Data)
ELSE NULL END as concatedvalues
FROM temp.dbo.TABLE1 AS T1
LEFT JOIN temp.dbo.TABLE2 AS T2 ON T1.CID = T2.CID AND T1.PID = T2.PID AND T1.SSC = T2.SSC
CID PID concatedvalues
1001 1333 OP2001150519952012
1002 1245 OR20131005 OR20131005
1003 1116 OP20131415 OP2013141520131516
1004 1234 OP2001150519952012
My suggestion(if there are default dates such as 1900-01-01, SQL server will treat them as Blank('') (as for date field blank('') means 1900-01-01')) in cases where 1900 should be treated as valid dates. If you just need to compare null fields try to use null or not null condition instead of isnull(date,'')= ''

Grouping similar items recursively

I have been reading the following Microsoft article on recursive queries using CTE and just can't seem to wrap my head around how to use it for group common items.
I have a table the contains the following columns:
ID
FirstName
LastName
DateOfBirth
BirthCountry
GroupID
What I need to do is start with the first person in the table and iterate through the table and find all the people that have the same (LastName and BirthCountry) or have the same (DateOfBirth and BirthCountry).
Now the tricky part is that I have to assign them the same GroupID and then for each person in that GroupID, I need to see if anyone else has the same information and then put the in the same GroupID.
I think I could do this with multiple cursors but it is getting tricky.
Here is sample data and output.
ID FirstName LastName DateOfBirth BirthCountry GroupID
----------- ---------- ---------- ----------- ------------ -----------
1 Jonh Doe 1983-01-01 Grand 100
2 Jack Stone 1976-06-08 Grand 100
3 Jane Doe 1982-02-08 Grand 100
4 Adam Wayne 1983-01-01 Grand 100
5 Kay Wayne 1976-06-08 Grand 100
6 Matt Knox 1983-01-01 Hay 101
John Doe and Jane Doe are in the same Group (100) because they have the same (LastName and BirthCountry).
Adam Wayne is in Group (100) because he has the same (BirthDate and BirthCountry) as John Doe.
Kay Wayne is in Group (100) because she has the same (LastName and BirthCountry) as Adam Wayne who is already in Group (100).
Matt Knox is in a new group (101) because he does not match anyone in previous groups.
Jack Stone is in a group (100) because he has the same (BirthDate and BirthCountry) as Kay Wayne who is already in Group (100).
Data scripts:
CREATE TABLE #Tbl(
ID INT,
FirstName VARCHAR(50),
LastName VARCHAR(50),
DateOfBirth DATE,
BirthCountry VARCHAR(50),
GroupID INT NULL
);
INSERT INTO #Tbl VALUES
(1, 'Jonh', 'Doe', '1983-01-01', 'Grand', NULL),
(2, 'Jack', 'Stone', '1976-06-08', 'Grand', NULL),
(3, 'Jane', 'Doe', '1982-02-08', 'Grand', NULL),
(4, 'Adam', 'Wayne', '1983-01-01', 'Grand', NULL),
(5, 'Kay', 'Wayne', '1976-06-08', 'Grand', NULL),
(6, 'Matt', 'Knox', '1983-01-01', 'Hay', NULL);
Here's what I came up with. I have rarely written recursive queries so it was some good practice for me. By the way Kay and Adam do not share a birth country in your sample data.
with data as (
select
LastName, DateOfBirth, BirthCountry,
row_number() over (order by LastName, DateOfBirth, BirthCountry) as grpNum
from T group by LastName, DateOfBirth, BirthCountry
), r as (
select
d.LastName, d.DateOfBirth, d.BirthCountry, d.grpNum,
cast('|' + cast(d.grpNum as varchar(8)) + '|' as varchar(1024)) as equ
from data as d
union all
select
d.LastName, d.DateOfBirth, d.BirthCountry, r.grpNum,
cast(r.equ + cast(d.grpNum as varchar(8)) + '|' as varchar(1024))
from r inner join data as d
on d.grpNum > r.grpNum
and charindex('|' + cast(d.grpNum as varchar(8)) + '|', r.equ) = 0
and (d.LastName = r.LastName or d.DateOfBirth = r.DateOfBirth)
and d.BirthCountry = r.BirthCountry
), g as (
select LastName, DateOfBirth, BirthCountry, min(grpNum) as grpNum
from r group by LastName, DateOfBirth, BirthCountry
)
select t.*, dense_rank() over (order by g.grpNum) + 100 as GroupID
from T as t
inner join g
on g.LastName = t.LastName
and g.DateOfBirth = t.DateOfBirth
and g.BirthCountry = t.BirthCountry
For the recursion to terminate it's necessary to keep track of the equivalences (via string concatenation) so that at each level it only needs to consider newly discovered equivalences (or connections, transitivities, etc.) Notice that I've avoided using the word group to avoid bleeding into the GROUP BY concept.
http://rextester.com/edit/TVRVZ10193
EDIT: I used an almost arbitrary numbering for the equivalences but if you wanted them to appear in a sequence based on the lowest ID with each block that's easy to do. Instead of using row_number() say min(ID) as grpNum presuming, of course, that IDs are unique.
I assume groupid is the output you want which start from 100.
Even if groupid come from another table,then it is no problem.
Firstly,sorry for my "No cursor comments".Cursor or RBAR operation is require for this task.In fact after a very long time i met such requirement which took so long and I use RBAR operation.
if tommorrow i am able to do using SET BASE METHOD,then I will come and edit it.
Most importantly using RBAR operation make the script more understanding and I think it wil work for other sample data too.
Also give feedback about the performance and how it work with other sample data.
Alsi in my script you note that id are not in serial,and it do not matter,i did this in order to test.
I use print for debuging purpose,you can remove it.
SET NOCOUNT ON
DECLARE #Tbl TABLE(
ID INT,
FirstName VARCHAR(50),
LastName VARCHAR(50),
DateOfBirth DATE,
BirthCountry VARCHAR(50),
GroupID INT NULL
);
INSERT INTO #Tbl VALUES
(1, 'Jonh', 'Doe', '1983-01-01', 'Grand', NULL) ,
(2, 'Jack', 'Stone', '1976-06-08', 'Grand', NULL),
(3, 'Jane', 'Doe', '1982-02-08', 'Grand', NULL),
(4, 'Adam', 'Wayne', '1983-01-01', 'Grand', NULL),
(5, 'Kay', 'Wayne', '1976-06-08', 'Grand', NULL),
(6, 'Matt', 'Knox', '1983-01-01', 'Hay', NULL),
(7, 'Jerry', 'Stone', '1976-06-08', 'Hay', NULL)
DECLARE #StartGroupid INT = 100
DECLARE #id INT
DECLARE #Groupid INT
DECLARE #Maxid INT
DECLARE #i INT = 1
DECLARE #MinGroupID int=#StartGroupid
DECLARE #MaxGroupID int=#StartGroupid
DECLARE #LastGroupID int
SELECT #maxid = max(id)
FROM #tbl
WHILE (#i <= #maxid)
BEGIN
SELECT #id = id
,#Groupid = Groupid
FROM #Tbl a
WHERE id = #i
if(#Groupid is not null and #Groupid<#MinGroupID)
set #MinGroupID=#Groupid
if(#Groupid is not null and #Groupid>#MaxGroupID)
set #MaxGroupID=#Groupid
if(#Groupid is not null)
set #LastGroupID=#Groupid
UPDATE A
SET groupid =case
when #id=1 and b.groupid is null then #StartGroupid
when #id>1 and b.groupid is null then #MaxGroupID+1--(Select max(groupid)+1 from #tbl where id<#id)
when #id>1 and b.groupid is not null then #MinGroupID --(Select min(groupid) from #tbl where id<#id)
end
FROM #Tbl A
INNER JOIN #tbl B ON b.id = #ID
WHERE (
(
a.BirthCountry = b.BirthCountry
and a.DateOfBirth = b.dateofbirth
)
or (a.LastName = b.LastName and a.BirthCountry = b.BirthCountry)
or (a.LastName = b.LastName and a.dateofbirth = b.dateofbirth)
)
--if(#id=7) --#id=2,#id=3 and so on (for debug
--break
SET #i = #i + 1
SET #ID = #I
END
SELECT *
FROM #Tbl
Alternate Method but still it return 56,000 rows without rownum=1.See if it work with other sample data or see if you can further optimize it.
;with CTE as
(
select a.ID,a.FirstName,a.LastName,a.DateOfBirth,a.BirthCountry
,#StartGroupid GroupID
,1 rn
FROM #Tbl A where a.id=1
UNION ALL
Select a.ID,a.FirstName,a.LastName,a.DateOfBirth,a.BirthCountry
,case when ((a.BirthCountry = b.BirthCountry and a.DateOfBirth = b.dateofbirth)
or (a.LastName = b.LastName and a.BirthCountry = b.BirthCountry)
or (a.LastName = b.LastName and a.dateofbirth = b.dateofbirth)
) then b.groupid else b.groupid+1 end
, b.rn+1
FROM #tbl A
inner join CTE B on a.id>1
where b.rn<#Maxid
)
,CTE1 as
(select * ,row_number()over(partition by id order by groupid )rownum
from CTE )
select * from cte1
where rownum=1
Maybe you can run it in this way
SELECT *
FROM table_name
GROUP BY
FirstName,
LastName,
GroupID
HAVING COUNT(GroupID) >= 2
ORDER BY GroupID

SQL SUM Values need and then AVG of 2 Tables

From this it is possible for the following :
TABLE 1
Id | final | Date
------------------
1 236 02-11-14
2 10 07-01-12
3 58 09-02-10
TABLE 2
Id | final | Date
------------------
1 330 02-11-14
2 5 07-01-12
3 100 09-02-10
ADD both Table 1 and Table 2 Sum'd values(column final), and then work out the AVG number from this and create this as another column average, THEN if table2 for example SUM'd original amount (before the AVG) is higher than Table 1 SUM'd amount create another column and print in that column 'Tbl2 has the higher amount' and vise verser if table 1 had the higher amount.
End result Column wise table would look like this :
|tb1_final_amount|tb2_final_amount|Avg_Amount|Top_Score_tbl
|tb1_final_amount|tb2_final_amount|Avg_Amount|Top_Score_tbl
304 435 369.5 tb2 has highest score
This is one way (of many) to do this. You can sum up the two tables and use them as derived tables in a query like so:
select
tb1_final_amount,
tb2_final_amount,
(tb1_final_amount+tb2_final_amount)/2.0 as Avg_Amount,
case
when tb1_final_amount < tb2_final_amount then 'tb2 has highest score'
else 'tb1 has highest score'
end as Top_Score_tbl
from
(select SUM(final) as tb1_final_amount from TABLE1) t1,
(select SUM(final) as tb2_final_amount from TABLE2) t2
This does the trick!:
--SET UP Table1
CREATE TABLE Table1 (ID INT, final INT, [Date] DATETIME)
INSERT Table1 VALUES (1, 236, '20141102')
INSERT Table1 VALUES (2, 10, '20120107')
INSERT Table1 VALUES (3, 58, '20100209')
--SET UP Table2
CREATE TABLE Table2 (ID INT, final INT, [Date] DATETIME)
INSERT Table2 VALUES (1, 330, '20141102')
INSERT Table2 VALUES (2, 5, '20120107')
INSERT Table2 VALUES (3, 100, '20100209')
-- Query
SELECT
SUM(CASE WHEN t.TableName = 'Table1' THEN T.final
ELSE 0
END) AS tb1_final_amount,
SUM(CASE WHEN t.TableName = 'Table2' THEN T.final
ELSE 0
END) AS tb2_final_amount,
AVG(T.final) AS Avg_Amount,
ISNULL((
SELECT
'Table1'
FROM
Table1 T1
WHERE
SUM(CASE WHEN t.TableName = 'Table1' THEN T.final
ELSE 0
END) > SUM(CASE WHEN t.TableName = 'Table2' THEN T.final
ELSE 0
END)
), 'Table2')
FROM
(
SELECT
'Table1' AS TableName,
final
FROM
Table1
UNION ALL
SELECT
'Table2',
final
FROM
Table2
) AS T

SQL Query - Multiple Table Join With Grouping Functions that Keep Branch Structure

I have exhausted my search for a solution and would like to post my question to see if a solution exists.
I need to write a report to show the debits and credits per branch. The report needs also show if branches have had no DBs or CRs.
For simplicity I have scaled down my tables to try highlight my issue.
My first table holds my Branch Data
BranchNo BranchName
1 Main
2 Mgorogoro
3 Arusha
My second table holds all Debit Transactions
txid Narrative Amount Date BranchNo
1 Test 1 50.00 2014/11/26 1
2 Test 2 20.00 2014/11/27 3
I've written a SQL statement that gives me the results I need:-
DECLARE #get_Dates CURSOR;
DECLARE #Date VarChar(10);
DECLARE #tbl TABLE
(
DebitOutCount int,
BranchCode VarChar(250),
TxDate VarChar(10)
)
--DECLARE #tbl TABLE(Idx1 VarChar(50), Idx8 VarChar(50), Idx3 VarChar(50))
SET #get_Dates = CURSOR FOR
Select Debits_OUT.Date FROM Debits_OUT GROUP BY Debits_OUT.Date ORDER BY Debits_OUT.Date
OPEN #get_Dates;
FETCH NEXT FROM #get_Dates into #Date;
WHILE (##FETCH_STATUS = 0)
BEGIN
--INSERT INTO #tbl SELECT Idx1, Idx8, Idx3 FROM SessionDailyControl WHERE Idx1 = #sessionId
INSERT INTO #tbl
SELECT
(SELECT ISNULL(SUM(DB_OUT.Amount), 0) FROM Debits_OUT AS DB_OUT WHERE B.BranchNo = DB_OUT.BranchNo AND DB_OUT.Date = #Date) AS DebitOutValue,
CAST(B.BranchNo As VarChar(10)) + ' ' + B.BranchName As [Branch Names],
#Date
From exBranches As B
FETCH NEXT FROM #get_Dates into #Date
END
CLOSE #get_Dates
DEALLOCATE #get_Dates
SELECT * FROM #tbl
The result is in the format that I need:-
DebitOutCount BranchCode TxDate
50 1 Main 2014/11/26
0 2 Mgorogoro 2014/11/26
0 3 Arusha 2014/11/26
0 1 Main 2014/11/27
0 2 Mgorogoro 2014/11/27
20 3 Arusha 2014/11/27
However, the report tools and Views cannot work with the above. I have tried Left Joins - but the problem is the result set will not keep the branch numbers for dates where there were zero transactions. For Example:-
SELECT
ISNULL(SUM(B.Amount), 0),
CAST(A.BranchNo As VarChar(10)) + ' ' + A.BranchName As [Branch Names],
B.Date
From exBranches As A
LEFT JOIN Debits_OUT AS B ON A.BranchNo = B.BranchNo
GROUP BY B.Date, A.BranchNo, A.BranchName
ORDER BY B.Date, A.BranchNo, A.BranchName
Returns:-
DB_OUT Branch Names Date
0.00 2 Mgorogoro NULL
50.00 1 Main 2014/11/26
20.00 3 Arusha 2014/11/27
In all the JOIN combinations that I try, I cannot get the branches to show ALL the branches for each date that is in the debits table.
Is there a fundamental concept that I have completely missed? I need have a query that can be run in a view that returns the same data as the cursor statement. Is this possible?
The idea is to generate possible combinations of Branches and dates first:
create table exBranches(
BranchNo int,
BranchName varchar(20)
)
create table Debits_OUT(
txId int,
Narrative varchar(20),
Amount decimal (6,2),
[Date] date,
BranchNo int
)
insert into exBranches values (1, 'Main'), (2, 'Mgorogoro'), (3, 'Arusha')
insert into Debits_OUT values (1, 'Test 1', 50.00, '20141126', 1), (2, 'Test 2', 20.00, '20141127', 3);
with BranchDate as(
select
b.BranchNo,
b.BranchName,
d.Date
from exBranches b
cross join (
select distinct [Date] from Debits_OUT
)d
)
select
isnull(DebitOutCount,0),
cast(b.BranchNo as varchar(10)) + ' ' + b.BranchName as BranchName,
b.Date
from BranchDate b
left join (
select
branchNo,
[Date],
sum(Amount) as DebitOutCount
from Debits_OUT
group by
BranchNo, [Date]
)d
on d.BranchNo = b.BranchNo
and d.Date = b.Date
order by b.date, b.BranchNo asc
drop table exBranches
drop table Debits_OUT
Try This it's works.....
select BranchName,amount,date1,BranchNo into #temp from exBranches
cross join (select distinct date1,amount from Debits_OUT)a
select isnull(t.amount,0),a.BranchName,a.date1 from #temp a
left join Debits_OUT t on t.BNo=a.BranchNo and a.date1=t.date1
order by date1
view here..
http://sqlfiddle.com/#!3/ad815/1

How do I get distinct COUNT in pivot?

I have a following table:
State LAB GROUP DATE CODE ID
UP A I 1-Jan 1 345
UP R S 1-Feb 1 456
UP A S 1-Jan 2 567
DL R S 1-Feb 3 678
DL T S 1-Jan 1 789
DL A S 1-Jan 2 900
MN T S 1-Jan 3 1011
MN R I 1-Feb 1 1122
MN S I 1-Feb 2 1233
I need a pivot table of following type:
STATE A R T TOTAL
UP 2 1 0 3
DL 1 1 1 3
MN 0 1 1 2
DISTINCT COUNT OF ID FOR EACH LAB FOR EACH STATE.
I then need the pivot tables filtered for following columns:
GROUP
DATE
CODE
So 1st table will have the pivot table above counting only those records which have GROUP=S
2nd table will have the pivot table above counting only those records which have CODE=1
and so on, I wish to put multiple conditions. and generate several tables one by one and export them.
If this is possible in SQL please let me know! I ruled out excel vba due to the size of table (source table will have 800,000 records approx).
Try this :-
Select [State],[A],[R],[T],Total = [A] + [R]+ [T]
from
(
Select [State],
[A] = Sum(Case when LAB='A' then 1 else 0 END) ,
[R] = Sum(Case when LAB='R' then 1 else 0 END) ,
[T] = Sum(Case when LAB='T' then 1 else 0 END)
from YourTable
group by [State]
)a
SQL FIDDLE
CREATE TABLE #t(States VARCHAR(10),LAB VARCHAR(5),GROUPs VARCHAR(5),DATEs VARCHAR(10),CODE INT,ID INT)
INSERT INTO #t values('UP','A','I','1-Jan',1,345)
INSERT INTO #t values('UP','R','S','1-Feb',1,456)
INSERT INTO #t values('UP','A','S','1-Jan',2,567)
INSERT INTO #t values('DL','R','S','1-Feb',3,678)
INSERT INTO #t values('DL','T','S','1-Jan',1,789)
INSERT INTO #t values('DL','A','S','1-Jan',2,900)
INSERT INTO #t values('MN','T','S','1-Jan',3,1011)
INSERT INTO #t values('MN','R','I','1-Feb',1,1122)
INSERT INTO #t values('MN','S','I','1-Feb',2,1233)
SELECT States,ISNULL(A,0) A,ISNULL(R,0) R,ISNULL(T,0) T,ISNULL(A,0)+ISNULL(R,0)+ISNULL(T,0) total
FROM
(
SELECT States,LAB,Count(ID) AS cnt FROM #t GROUP BY States,LAB /*apply GROUP DATE CODE condition here*/
) AS PVT
PIVOT(MAX(cnt) FOR LAB IN (A,R,T)) pvt
Another solution using PIVOT :
WITH PivotInUse AS (
SELECT state,lab,COUNT(*) AS cnt
FROM YourTable
GROUP BY state,lab
)
SELECT STATE
,COALESCE([A], 0) AS A
,COALESCE([R], 0) AS R
,COALESCE([T], 0) AS T
,COALESCE([A], 0) + COALESCE([R], 0) + COALESCE([T], 0) AS TOTAL
FROM PivotInUse
PIVOT(SUM(cnt) FOR lab IN ([A],[R],[T])) AS p;
Your sample table
SELECT * INTO #TEMP FROM
(
SELECT 'UP' [State],'A' LAB,'I' [GROUP],'1-Jan' [DATE],1 CODE,345 ID
UNION ALL
SELECT 'UP','R','S','1-Feb',1,456
UNION ALL
SELECT 'UP','A','S','1-Jan',2,567
UNION ALL
SELECT 'DL','R','S','1-Feb',3,678
UNION ALL
SELECT 'DL','T','S','1-Jan',1,789
UNION ALL
SELECT 'DL','A','S','1-Jan',2,900
UNION ALL
SELECT 'MN','T','S','1-Jan',3,1011
UNION ALL
SELECT 'MN','R','I','1-Feb',1,1122
UNION ALL
SELECT 'MN','S','I','1-Feb',2,1233
)TAB
Now you need to get the distinct count of each state and get the sum as the result to show Total
in pivoted result.
SELECT DISTINCT [State],LAB,SUM(CNT) CNT
INTO #NEWTABLE
FROM
(
SELECT DISTINCT
[State],LAB,
CASE WHEN [State] IS NULL THEN NULL ELSE COUNT([State]) OVER(PARTITION BY [State],LAB) END CNT
FROM #TEMP
)TAB
GROUP BY [State],LAB
WITH ROLLUP
Now we need to get the distinct columns for pivot(#cols) and columns to identify and replace null with zero in pivot(#NullToZeroCols)
DECLARE #cols NVARCHAR (MAX)
DECLARE #NullToZeroCols NVARCHAR (MAX)
SET #cols = SUBSTRING((SELECT DISTINCT ',['+LAB+']' FROM #NEWTABLE GROUP BY LAB FOR XML PATH('')),2,8000)
SET #NullToZeroCols = SUBSTRING((SELECT DISTINCT ',ISNULL(['+LAB+'],0) AS ['+LAB+']'
FROM #NEWTABLE GROUP BY LAB FOR XML PATH('')),2,8000)
Join the pivotted query with the #NEWTABLE to get the Total for each State
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT P.State,' + #NullToZeroCols + ',T2.CNT TOTAL FROM
(
SELECT DISTINCT [State],LAB,CNT FROM #NEWTABLE
) x
PIVOT
(
SUM(CNT)
FOR [LAB] IN (' + #cols + ')
) p
JOIN #NEWTABLE T2 ON P.[STATE]=T2.[STATE]
WHERE P.State IS NOT NULL AND T2.LAB IS NULL AND T2.[STATE] IS NOT NULL;'
EXEC SP_EXECUTESQL #query
Here is your result
Here is the SQLFiddle http://sqlfiddle.com/#!3/c2588/1 (If it shows any error while loading the page, just click RUNSQL, it will work)
Now if you want to get the result as you said DISTINCT COUNT OF ID FOR EACH LAB FOR EACH STATE, just change
OVER(PARTITION BY [State],LAB)
to
OVER(PARTITION BY [State],LAB,Id)
which will show the following result after executing the pivot query

Resources