I would like to sum a group of sums in sql - sql

I would like get the totals for a dealer on one line. How do I go about adding that to this stored procedure?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
exec sysdba.aa_Distinguished_Dealer
*/
ALTER PROCEDURE [sysdba].[aa_Distinguished_Dealer]
AS
BEGIN
declare #baseDate datetime
declare #i int
declare #sql varchar(max)
declare #RollingDate date
declare #startOfMonth varchar(32)
set #baseDate = GETUTCDATE()
set #i = -1
if OBJECT_ID('tempdb..#rebate') is not null
drop table #rebate
create table #rebate
(
AccountId char(12),
DealerOfRecord varchar(64),
OrderTotal float,
OrderCount int,
DistinguishedDealerDate date
)
while #i > -2
begin
set #RollingDate = DATEADD(month, #i , #baseDate)
set #startOfMonth = cast(MONTH(#RollingDate) as varchar(2)) + '/1/' + cast(YEAR(#RollingDate) as CHAR(4))
set #sql = 'insert into #rebate select AccountID, DEALEROFRECORD, SUM(ORDERTOTAL) OrderTotal, COUNT(*) OrderCount, ''' + #startOfMonth + ''' DistinguishedDealerDate from sysdba.vDistinguishedDealer
where cast(convert(varchar(32), ORDERDATE, 101) as datetime) between dateadd(year, -1,''' + #startOfMonth + ''') and cast(''' + #startOfMonth + ''' as datetime)
group by AccountID, DEALEROFRECORD'
exec(#sql)
set #i = #i - 1
end
if OBJECT_ID('tempdb..#rebateResults') is not null
drop table #rebateResults
create table #rebateResults
([Rep Code] varchar(3),
[Acct. #] varchar(32),
AccountId char(12),
[Customer Name] varchar(64),
City varchar(32),
[State] varchar(32),
DDLevel varchar(32),
OrderTotal Float,
OrderCount int,
DDException varchar(2000)
)
insert into #rebateResults
select AccountId, DealerOfRecord, 'Elite', sum(OrderTotal), SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 500000 and isnull(AccountId, '') != ''
group by AccountId, DealerOfRecord
insert into #rebateResults
select AccountId, DealerOfRecord, 'Standard', sum(OrderTotal), SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 100000 and OrderTotal < 500000 and isnull(AccountId, '') != ''
group by AccountId, DealerOfRecord
select * from #rebateResults
end

As I continue to hone my SQL skills, I have begun to stop doing this in the SQL code and left it to the reporting software, but if you want it straight from the sproc... use GROUPING SETS
select CASE WHEN GROUPING (AccountId) = 1 THEN 'Total for Dealer' ELSE AccountId END AS AccountId,
DealerOfRecord,
'Elite',
sum(OrderTotal),
SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 500000 and isnull(AccountId, '') != ''
group by GROUPING SETS ((AccountId, DealerOfRecord),(DealerOfRecord))
insert into #rebateResults
select CASE WHEN GROUPING (AccountId) = 1 THEN 'Total for Dealer' ELSE AccountId END AS AccountId,
DealerOfRecord,
'Standard',
sum(OrderTotal),
SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 100000 and OrderTotal < 500000 and isnull(AccountId, '') != ''
group by GROUPING SETS ((AccountId, DealerOfRecord),(DealerOfRecord))

Related

Values are not returned for Fromdate and ToDate columns

I have created a stored procedure for bulk invoice generation. On execution of the stored procedure, the values are successfully returned for all the columns except FromDate and ToDate. For these 2 columns, NULL values are displaying.
This here is the procedure that I have created. Please let me know what I am doing wrong here?
SET #fromDt = CONVERT(VARCHAR, DATEADD(d, -(DAY(DATEADD(m, -1, #currentdate - 2))), DATEADD(m, -1, #currentdate - 1)), 106)
ALTER PROCEDURE Bulkinvoicegeneration_lko
#InvoiceMonth VARCHAR(20),
#PrjId BIGINT,
#CustomerId NVARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #fromDt DATETIME,
#monthdays INT,
#ToDate DATETIME,
#Currentdate DATETIME,
#Year INT
SET #currentdate = CONVERT(VARCHAR, #Year) + '-'
+ CONVERT(VARCHAR, #InvoiceMonth) + '-11'
SET #fromDt = CONVERT(VARCHAR, DATEADD(d, - (DAY(DATEADD(m, -1, #currentdate - 2))), DATEADD(m, -1, #currentdate - 1)), 106)
SET #ToDate = CONVERT(DATE, Dateadd(d, -(Day(#currentdate)), #currentdate))
SET #monthdays = DATEDIFF(d, #fromDt, #ToDate) + 1
SELECT *
INTO #consumerdata1
FROM
(SELECT
id, prjid, customerid, ucccatid, area, rate,
billingamount AS TotalAmt,
billingamount AS SubTotalAmt
FROM
consumermst_lko
WHERE
1 = 2) AS aa
BEGIN
INSERT INTO #consumerdata1
SELECT
prjid, customerid, ucccatid, area, rate,
billingamount AS TotalAmt,
billingamount AS SubTotalAmt
FROM
consumermst_lko
END
ALTER TABLE #consumerdata1
ADD invoiceno VARCHAR(20), invoicedate DATE, duedate DATE,
balanceamt NUMERIC(10, 2), roundoff NUMERIC(10, 2),
entrydate DATE, fromdate DATE, todate DATE,
userid INT, deleteflag INT, responsecode INT,
responsemessage VARCHAR(500), invoiceno_response VARCHAR(500)
UPDATE #consumerdata1
SET entrydate = Getdate()
UPDATE #consumerdata1
SET userid = 2
UPDATE #consumerdata1
SET balanceamt = 20
--update #CONSUMERDATA set billingdays = 30
UPDATE #consumerdata1
SET invoiceno = NULL,
invoicedate = CONVERT(DATE, GETDATE() - 1),
duedate = DATEADD(d, 15, CONVERT(DATE, GETDATE())),
roundoff = 0,
deleteflag = 0
DECLARE #id BIGINT,
#InvoiceNo NVARCHAR(150),
#InvoiceDate DATE,
#DueDate DATE,
#UccCatId BIGINT,
#rate NUMERIC(10, 2),
#Area NUMERIC(10, 2),
#TotalAmt NUMERIC(10, 2),
#BalanceAmt NUMERIC(10, 2),
#SubTotalAmt NUMERIC(10, 2),
#RoundOff NUMERIC(10, 2),
#EntryDate DATE,
#FromDate DATE,
#UserId BIGINT,
#deleteflag INT,
#RESPONSECODE INT,
#RESPONSEMESSAGE VARCHAR(255),
#INVOICENO_RESPONSE VARCHAR(20)
SET #prjid = 2
DECLARE consmr_cursor1 CURSOR FOR
SELECT
id, prjid, customerid, ucccatid, area, rate,
totalamt, subtotalamt, invoiceno, invoicedate, duedate,
balanceamt, roundoff, entrydate, fromdate, todate,
userid, deleteflag, responsecode, responsemessage,
invoiceno_response
FROM
#consumerdata1
OPEN consmr_cursor1
FETCH NEXT FROM consmr_cursor1
INTO #Id, #PrjId, #CustomerId, #UccCatId, #Area, #rate, #TotalAmt, #SubTotalAmt, #InvoiceNo, #InvoiceDate, #DueDate,
#BalanceAmt, #RoundOff, #EntryDate, #FromDate, #ToDate, #UserId, #deleteflag,
#ResponseCode, #ResponseMessage, #INVOICENO_RESPONSE
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC [dbo].[Demoinvoice]
#Id = #Id,
#InvoiceNo =#InvoiceNo,
#PrjId = #PrjId,
#CustomerId = #CustomerId,
#InvoiceDate = #InvoiceDate,
#InvoiceMonth = #InvoiceMonth,
#DueDate = #DueDate,
#UccCatId = #UccCatId,
#Rate = #Rate,
#Quantity = #Area,
#TotalAmt = #TotalAmt,
#BalanceAMT = #BalanceAmt,
#SubTotalAmt = #SubtotalAmt,
#RoundOff = #RoundOff,
#EntryDate = #EntryDate,
#FromDate = #FromDate,
#ToDate = #ToDate,
#UserId = #UserId,
#deleteflag = #deleteflag,
#RESPONSECODE = #RESPONSECODE,
#RESPONSEMESSAGE = #RESPONSEMESSAGE output,
#INVOICENO_RESPONSE = #INVOICENO_RESPONSE output
UPDATE #consumerdata1
SET responsecode = #RESPONSECODE,
responsemessage = #RESPONSEMESSAGE,
invoiceno_response = #INVOICENO_RESPONSE
WHERE customerid = #CustomerId
FETCH NEXT FROM consmr_cursor1
INTO #Id, #PrjId, #CustomerId, #UccCatId, #Area, #rate, #TotalAmt, #SubTotalAmt, #InvoiceNo, #InvoiceDate,
#DueDate, #BalanceAmt, #RoundOff, #EntryDate, #FromDate, #ToDate, #UserId, #deleteflag,
#ResponseCode, #ResponseMessage, #INVOICENO_RESPONSE
END
CLOSE consmr_cursor1
DEALLOCATE consmr_cursor1
SELECT *
FROM #consumerdata1
-- WHERE #RESPONSECODE <> 200
END
EXECUTE Bulkinvoicegeneration_lko
1,
2,
'LKO00066801'
Check this section in your procedure
DECLARE #fromDt DATETIME,
#monthdays INT = 10,
#ToDate DATETIME,
#Currentdate DATETIME,
#Year INT , ---- you need to pass some value over there
#InvoiceMonth varchar(50) = '1' --- this is passed as parameter from your procedure
SET #currentdate = CONVERT(VARCHAR, #Year) + '-'
+ CONVERT(VARCHAR, #InvoiceMonth) + '-11'
Select #currentdate ---- this value is NULL, since #Year is not passed.
Since you are using #currentdate for generating your #frmdt and #todt so they are also NULL.
DECLARE #fromDt DATETIME,
#monthdays INT = 10,
#ToDate DATETIME,
#Currentdate DATETIME,
#Year INT = 2019,
#InvoiceMonth varchar(50) = '1' --- this is passed as parameter from your procedure
SET #currentdate = CONVERT(VARCHAR, #Year) + '-'
+ CONVERT(VARCHAR, #InvoiceMonth) + '-11'
Select #currentdate ---- this value is '2019-01-11 00:00:00.000'.
---- After that
SET #fromDt = CONVERT(VARCHAR, DATEADD(d, - (DAY(DATEADD(m, -1, #currentdate - 2))), DATEADD(m, -1, #currentdate - 1)), 106)
SET #ToDate = CONVERT(DATE, Dateadd(d, -(Day(#currentdate)), #currentdate))
SET #monthdays = DATEDIFF(d, #fromDt, #ToDate) + 1
RESULT
frmdt toDate Monthdays
2018-12-01 00:00:00.000 2018-12-31 00:00:00.000 31
Update your code for setting this #currentdate once it is done hope rest of the block will fit on right place for you.... ;)
One thing I noticed is that you are not initializing the variable #year before using it.
If you want to set it to the current year, you can
SET #Year = year(getdate())
Add year parameter on this procedure.
ALTER PROCEDURE Bulkinvoicegeneration_lko #InvoiceMonth VARCHAR(20),
#PrjId BIGINT,
#CustomerId NVARCHAR(50),
#InvoiceYear INT
Then SET #Year = #InvoiceYear
Or SET YOUR #Year INT = 2019

Adding Missing Month in T-SQL

I have a data something like this:
LoanId PaymentDate PaymentMonth PaymentAmount
L1 12-01-2008 01 100
L2 15-02-2008 02 300
L3 01-04-2008 04 500
L3 01-10-2008 10 500
I want to add missing PaymentMonth's for each loanId's, like this:
LoanId PaymentYear PaymentMonth PaymentAmount
L1 2008 01 100
L1 2008 02 0
L1 2008 03 0
.. .. .. ..
L1 2008 12 0
L2 2008 01 0
L2 2008 02 300
L2 2008 03 0
.. .. .. ..
L3 2008 01 0
L3 2008 02 0
L3 2008 03 0
L3 2008 04 500
.. .. .. ..
L3 2008 10 500
.. .. .. ..
L3 2008 12 0
Was doing it manually, but now got more than 100k LoanId's from 2008-20012
Try to do this:
use db_test;
go
create table dbo.test1
(
loanId varchar(2),
paymentDate date,
paymentMonth varchar(2),
paymentAmount float
);
set dateformat dmy;
insert into dbo.test1
values
('L1', '12-01-2008', '01', 100),
('L2', '15-02-2008', '02', 300),
('L3', '01-04-2008', '04', 500),
('L3', '01-10-2008', '10', 500);
set dateformat ymd;
with cte as (
select cast('2008-01-31' as date) as month_dt, 1 as month_nm, format(1, 'd2') as paymentMonth
union all
select eomonth(dateadd(month, 1, month_dt)), month_nm + 1, format(month(month_dt) % 12 + 1, 'd2')
from cte
where month_dt < '2012-12-31'
), cte2 as (
select
t.loanId,
x.month_dt,
x.paymentMonth
from (
select distinct loanId from dbo.test1
) t
join cte x
on 1 = 1
)
select
a.loanId, year(a.month_dt) as paymentYear, a.paymentMonth, coalesce(b.sm, 0) as paymentAmount
from
cte2 a
left join (
select loanId, eomonth(paymentDate) as paymentDate, paymentMonth, sum(paymentAmount) as sm
from dbo.test1
group by loanId, eomonth(paymentDate), paymentMonth
) b
on a.month_dt = b.paymentDate
and a.loanId = b.loanId
order by
paymentYear asc,
loanId asc,
paymentMonth;
you could try like:
1.) Getting your MIN & MAX PaymentDate (as i asume those are the your ranges)
2.) Creating all months within this range - in my example with a common table expression).
3.) Finally selecting your data and joining with those month-dates and grouping the result
DECLARE #StartDate DATETIME,
#EndDate DATETIME;
SET #StartDate = SELECT MIN(PaymentDate)
FROM yourtable
SET #EndDate = SELECT MAX(PaymentDate)
FROM yourtable
;WITH CTE AS (
SELECT DATEADD(MONTH, x.number, #StartDate) as Months
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #StartDate, #EndDate)
)
SELECT yourtable.LoanID
,yourtable.PaymentYear
,yourtable.PaymentMonth
,SUM(ISNULL(PaymentAmount,0)) as PaymentAmount
FROM CTE
INNER JOIN yourtable
ON yourtable.PaymentYear = CONVERT(VARCHAR(4),DATEPART(YEAR, Months))
AND yourtable.PaymentMonth = RIGHT('0' + CONVERT(VARCHAR(2),DATEPART(MONTH, Months)),2)
GROUP BY yourtable.LoanID
,yourtable.PaymentYear
,yourtable.PaymentMonth
This is one way of doing it, pretty straightforward. Necessary comments are in the code.
declare #LoanData table (
ID char(2),
PaymentDate date,
PaymentAmount int
)
insert into #LoanData values
('L1', '01-12-2008',100),
('L2', '02-15-2008',300),
('L3', '04-01-2008',500),
('L3', '10-01-2008',500)
declare #TableID table(id char(2))
--list of IDs
insert into #TableID select distinct ID from #LoanData
declare #PaymentMonth table(
LoanID char(2),
PaymentYear int,
PaymentMonth int,
PaymentAmount int
)
declare #month int, #year int, #i int, #id char(2)
select #i = count(*) from #TableID
--first get the table which has recotrd for every month for every id (default value in PaymentAmount is 0)
while #i > 0
begin
select top 1 #id = id from #TableID
set #year=2008
while #year <= 2012
begin
set #month=1
while #month <= 12
begin
insert into #PaymentMonth values (#id, #year, #month, 0)
set #month = #month + 1
end
set #year = #year + 1
end
delete from #TableID where id = #id
set #i = #i - 1
end
--update table based on your initial data
update #PaymentMonth
set PaymentAmount = A.PaymentAmount from #LoanData as A
where LoanID = A.ID and PaymentYear = datepart(YEAR, A.PaymentDate) and PaymentMonth = datepart(MONTH, A.PaymentDate)
select * from #PaymentMonth
create table temp_loantable (
loanid bigint,
paymentdate date,
paymentmonth varchar(2),
paymentamount numeric(10,2))
Having a date range ( year & month) and then doing a left outer join should get the desired output.
select * from
(select years.n yearval , months.n monthval
from (values(2008), (2009), (2010), (2011), (2012)) years(n),
(values(1),(2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) months(n)) a
left outer join temp_loantable l
on year(paymentdate) = a.yearval
and month(paymentdate) = a.monthval

Date functions in Stored Procedure

Overview : I want to show the weekly result by input parameters startdate and enddate. I am getting this result quite well. But the problem here is, When i want start date from 28/08/2015 from end date 04/09/2015 am getting 28, 29, 30, 31, 01, 02, 03, 04 from same month(august). Expected result should be 28, 29, 30, 31 from august and 01, 02, 03, 04 from september.
Help me to overcome this problem. Below is my code
ALTER PROCEDURE [dbo].[usp_Get_TimesheetDetails]
#UserID int, #startdate datetime, #enddate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #intStartDate int
declare #intEndDate int, #diff int
declare #strMonth varchar(50)
Select #intStartDate = DATEPART(day, #startDate)
Select #intEndDate = DATEPART(day, #endDate)
select #strMonth = DATENAME(MONTH, GETDATE())
Declare #temptable table (num date )
Declare #columns varchar(max)
DECLARE #sqlText nvarchar(1000);
DECLARE #startnum INT = #intStartDate-1
DECLARE #endnum INT = #intEndDate
select #diff = DATEDIFF(MONTH, #startdate, #enddate)
;WITH gen AS (
SELECT #startdate AS num
UNION ALL
SELECT DATEADD(DAY,1,num) FROM gen
WHERE DATEADD(DAY,1,num) <= #enddate
)
insert into #temptable SELECT num FROM gen
option (maxrecursion 10000)
set #columns=
(SELECT distinct
STUFF((SELECT ',' + CAST( DATEPART(DAY, num) as varchar(100)) [text()]
FROM #temptable
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM #temptable t)
if(#startnum < 10)
BEGIN
SET #sqlText = N'SELECT ' + STUFF(REPLACE(#columns,',','],['),1,3,'') + ']' + ' FROM dbo.timesheet where month ='''+ #strMonth+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')'
print #sqlText
END
else if(#startnum >= 10)
BEGIN
SET #sqlText = N'SELECT ' + STUFF(REPLACE(#columns,',','],['),1,4,'') + ']' + ' FROM dbo.timesheet where month ='''+ #strMonth+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')'
END
print #sqlText
Exec (#sqlText)
end
end
Edited : I tried with if else condition like, if(monthdifference is equal to 0)
else(monthdifference is greater than 0). But not getting expected result.
try this
Declare
#StartDate datetime='2015/08/28',
#EndDate datetime='2015/09/04'
;WITH sample AS (
SELECT CAST(#StartDate AS DATETIME) AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt)
FROM sample s
WHERE DATEADD(dd, 1, dt) <= CAST(#EndDate AS DATETIME))
SELECT *
FROM sample
output is :
2015-08-28 00:00:00.000
2015-08-29 00:00:00.000
2015-08-30 00:00:00.000
2015-08-31 00:00:00.000
2015-09-01 00:00:00.000
2015-09-02 00:00:00.000
2015-09-03 00:00:00.000
2015-09-04 00:00:00.000
Original Link : https://stackoverflow.com/a/3946151/3465753
Make sure you declared startdate as well as enddate in dynamic query
The main Ideas are:
You don't need to use STUFF. Just select dates from DATEADD(DAY,1,#startdate)
You should get dates twise if DATENAME(MONTH, #startdate)!=DATENAME(MONTH, #enddate). First time from startdate to end of months. Second time from start of second month to enddate.
My (checked) script.
ALTER PROCEDURE [dbo].[usp_Get_TimesheetDetails]
#UserID int, #startdate datetime, #enddate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #columns varchar(max);
DECLARE #sqlText nvarchar(1000);
Declare #temptable table (num date );
WITH gen AS (
SELECT DATEADD(DAY,1,#startdate) AS num
UNION ALL
SELECT DATEADD(DAY,1,num) FROM gen
WHERE DATEADD(DAY,1,num) <= #enddate
and DATEADD(DAY,1,num) < dateadd(month,datediff(month,0,#enddate),0)
)
insert into #temptable SELECT num FROM gen
option (maxrecursion 10000)
set #columns=
(SELECT distinct
STUFF((SELECT ',' + CAST( DATEPART(DAY, num) as varchar(100)) [text()]
FROM #temptable
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') List_Output
FROM #temptable t)
SET #sqlText = N'SELECT [' + REPLACE(#columns,',','],[') + ']' + ' FROM dbo.timesheet where month ='''+ DATENAME(MONTH, #startdate)+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')';
print #sqlText;
IF DATENAME(MONTH, #startdate)!=DATENAME(MONTH, #enddate)
BEGIN
delete from #temptable;
WITH gen AS (
SELECT dateadd(month,datediff(month,0,#enddate),0) AS num
UNION ALL
SELECT DATEADD(DAY,1,num) FROM gen
WHERE DATEADD(DAY,1,num) <= #enddate
)
insert into #temptable SELECT num FROM gen
option (maxrecursion 10000)
set #columns=
(SELECT distinct
STUFF((SELECT ',' + CAST( DATEPART(DAY, num) as varchar(100)) [text()]
FROM #temptable
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') List_Output
FROM #temptable t)
SET #sqlText = N'SELECT [' + REPLACE(#columns,',','],[') + ']' + ' FROM dbo.timesheet where month ='''+ DATENAME(MONTH, #enddate)+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')';
print #sqlText
end
end
You might find pivot/unpivot to be more robust. Certainly your table design is not ideal. (I pared down the number of columns for demonstration purposes.)
create table dbo.timesheet (
[month] varchar(12) not null,
[1] int null, [2] int null, [3] int null,
[28] int null, [29] int null, [30] int null, [31] int null
);
declare #startDate date = '20160628';
declare #endDate date = '20160703';
insert into dbo.timesheet ([month], [1], [2], [3], [28], [29], [30], [31])
values ('June', 1, 2, 3, 4, 5, 6, null), ('July', 8, 9, 10, 11, 12, 13, 14);
with hrs as (
select
hrs,
dy,
dateadd(
month,
case [month]
when 'January' then 1 when 'February' then 2 when 'March' then 3
when 'April' then 4 when 'May' then 5 when 'June' then 6
when 'July' then 7 when 'August' then 8 when 'September' then 9
when 'October' then 10 when 'November' then 11 when 'December' then 12
end,
dateadd(year, year(getdate()) - 2000, dateadd(day, dy - 1, '19991201'))
) as dt
from
(select [month], [1], [2], [3], [28], [29], [30], [31] from dbo.timesheet) t
unpivot (hrs for dy in ([1], [2], [3], [28], [29], [30], [31])) as upvt
)
select datename(month, dt), [1], [2], [3], [28], [29], [30], [31]
from hrs pivot (min(hrs) for dy in ([1], [2], [3], [28], [29], [30], [31])) as pvt
where dt between #startDate and #endDate;

The data types varchar and int are incompatible in the concat operator

I've been stuck for the past two days execute it give the error:
The data types varchar and int are incompatible in the concat operator
Here is my table:
create table salestable
(
id int identity(1,1) not null primary key,
empid char(5),
datesold date,
monthonly varchar(50),
amount money
)
This code inserts the dummy record into dbo.salestable for working in salestable, debug and step into the code that give the debug and understanding code
declare #outercounter int = 1
declare #innercounter int = 1
while #outercounter <= (select count(name) from namestable)
begin
while #innercounter <= datediff(day, getdate() -datepart(day, getdate()), {fn concat('12/31/',Datepart(year,getdate()))})
begin
insert into salestable (empid, datesold, monthonly, amount)
values (#outercounter,
getdate() - datepart(day, getdate()) + #innercounter,
Datename(month, getdate() - datepart(day, getdate()) + #innercounter),
rand() * 10000)
set #innercounter = #innercounter +1
end
set #outercounter = #outercounter + 1
set #innercounter = 1
end
select * from dbo.salestable
fn concat('12/31/',CAST(Datepart(year,getdate()) AS VARCHAR(10)))
Try this

SQL Server query to generate dynamic staff attendance report

I have a table to store staff attendance which has the following columns:
id: int, pk
StaffName: varchar
CompanyName: varchar
isPresent: varchar
date: datetime
How do I write a query which gives attendance of a month?
Eg: Generate report for April for a company XYZ, which should looks like
StaffName 1 2 3 4 5 6 7 8 9....up to last day of month
--------------------------------------------------------------
John lenon p p p a p a a p a....
Bob Dylan a a a p p p p p a....
Keith Moon p p p p a p a p p....
That can be a little bit tricky with qynamic queries. For the table:
CREATE TABLE [dbo].[attendance](
[id] [int] NOT NULL,
[StaffName] [varchar](100) NULL,
[CompanyName] [varchar](100) NULL,
[isPresent] [char](1) NULL,
[date] [datetime] NULL,
PRIMARY KEY CLUSTERED ( [id] ASC )
)
go
The following script generates 'pivot-compatible' script with days as columns
--report params
DECLARE #month int, #year int, #lastDay int
set #month = 1
set #year = 2012
-- calculations
DECLARE #startDate datetime, #endDate datetime
SET #startDate = convert(varchar, #year) + '-' + convert(varchar, #month) + '-1'
set #endDate = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#startDate)+1,0))
set #lastDay = day(#endDate) --last day of month
print('showing data from ' + convert(varchar, #startDate) + ' to ' + convert(varchar, #endDate))
print('original report')
SELECT StaffName, isPresent, day([date]) as day FROM attendance
where [date] between #startDate and #endDate
declare #day int
set #day = 2
declare #days varchar(max)
set #days = '[1]'
WHILE (#day <= #lastDay)
BEGIN
set #days = #days + ',[' + convert(varchar, #day) + ']'
set #day = #day + 1
END
-- select #days
declare #query varchar(max)
set #query = '
SELECT StaffName, ' + #days +
'
FROM
(SELECT StaffName, isPresent, day(date) as day FROM attendance) AS SourceTable
PIVOT
(
MAX(isPresent)
FOR day IN ( ' + #days + ')' + '
) AS PivotTable;'
--select #query
print('pivoted report')
exec(#query)
You can pivot your date as column with the PIVOT functionality(here a quick and dirty example, you may check date format and order):
SELECT StaffName, [0], [1], [2], [3], [4] and so on...
FROM
(SELECT StaffName, isPresent, date FROM myTable) AS SourceTable
PIVOT
(
MAX(isPresent)
FOR date IN ([0], [1], [2], [3], [4] and so on...)
) AS PivotTable;