Convert multiple Rows into Columns EDIT - sql

OK. I edit my question. This is my script:
CREATE TABLE #Table (
Data Date,
Max_Temp Real,
Min_Temp Real,
Sr_Temp Real,
Sr_Temp_work Real)
SET NOCOUNT ON
DECLARE #StartTime Time
DECLARE #EndTime Time
DECLARE #StartTime1 Time
DECLARE #EndTime1 Time
DECLARE #data_start Date
DECLARE #data_stop Date
DECLARE #Data Date
DECLARE #Data_stop_while Date
DECLARE #Max_Temp Real
DECLARE #Min_Temp Real
DECLARE #Sr_Temp Real
DECLARE #Sr_Temp_work Real
SET #data_start = '20140713'
SET #data_stop = '20140719'
SET #StartTime = '00:00:00.000'
SET #EndTime = '23:59:59.998'
SET #StartTime1 = '08:00:00.000'
SET #EndTime1 = '16:30:00.000'
Set NOCOUNT OFF
SELECT #Data = #data_start
SELECT #Data_stop_while = DATEADD(day,1,#data_stop)
WHILE (#Data_stop_while<>#Data)
BEGIN
SELECT #Max_Temp = MAX(Value), #Min_Temp = MIN(Value), #Sr_Temp = AVG(Value) FROM INSQL.Runtime.dbo.History WHERE TagName IN ('VariableName')
and wwRetrievalMode = 'Cyclic'
AND DateTime >= (#Data + cast(#StartTime as datetime))
AND DateTime <= (#Data + cast(#EndTime as datetime))
SELECT #Sr_Temp_work = AVG(Value) FROM INSQL.Runtime.dbo.History WHERE TagName IN ('VariableName')
and wwRetrievalMode = 'Cyclic'
AND DateTime >= (#Data + cast(#StartTime1 as datetime))
AND DateTime <= (#Data + cast(#EndTime1 as datetime))
INSERT INTO #Table(Data, Max_Temp, Min_Temp, Sr_Temp, Sr_Temp_work) VALUES (#Data, #Max_Temp, #Min_Temp, #Sr_Temp, #Sr_Temp_work)
SELECT #Data = DATEADD(day,1,#Data)
END
SELECT Data, Max_Temp, Min_Temp, Sr_Temp, Sr_Temp_work FROM #Table GO
When I set a specific time interval, I have those tables and now I need convert this table:
I used pivot, unpivot and any links with forums and I can't do it...

Actually you need to use dynamic pivot and unpivot together. Check the following query. Use the following code in place of the last select query in your procedure
DECLARE #Columns NVARCHAR(MAX)
DECLARE #MainQuery NVARCHAR(MAX)
SELECT #Columns = ISNULL( #Columns + ',','') + QUOTENAME(CONVERT(VARCHAR(10),Data,20))
FROM (SELECT DISTINCT Data FROM #Table) C
SET #MainQuery ='SELECT [Temperature],' + #Columns + '
FROM
(
SELECT Data,Max_Temp,Min_Temp,Sr_Temp,Sr_Temp_work
FROM #Table
) as T
UNPIVOT
(
Value FOR [Temperature] in (Max_Temp,Min_Temp,Sr_Temp,Sr_Temp_work)
) AS U
PIVOT
(
MAX(Value) FOR [Data] IN ('+ #Columns +')
) as P
'
EXEC sp_executesql #MainQuery

It's not by far the most elegant solution but with some dynamic SQL you should be able to replicate the logic.
DECLARE #temp TABLE (
Data DATE,
Max_temp FLOAT,
Min_Temp FLOAT,
Sr_Temp FLOAT,
Sr_Temp_work FLOAT
)
INSERT INTO #temp
select
*
from (values
('2014-07-13',25.8,25.6,25.701,25.668),
('2014-07-14',26.8,26.6,26.701,26.668),
('2014-07-15',27.8,27.6,27.701,27.668),
('2014-07-16',28.8,28.6,28.701,28.668))T (Data,Max_temp,Min_Temp,Sr_Temp, Sr_Temp_work)
SELECT
Data,
Max_temp,
Min_Temp,
Sr_Temp,
Sr_Temp_work
FROM #temp
SELECT
'Max_temp' Temperature,
MAX([2014-07-13])[2014-07-13],
MAX([2014-07-14])[2014-07-14],
MAX([2014-07-15])[2014-07-15],
MAX([2014-07-16])[2014-07-16]
FROM
(
SELECT
Data,
Max_temp,
Min_Temp,
Sr_Temp,
Sr_Temp_work
FROM #temp
) SRC
PIVOT (
MAX(Max_temp)
FOR Data IN ([2014-07-13],[2014-07-14],[2014-07-15],[2014-07-16])
) AS pvt
UNION ALL
SELECT
'Min_Temp' Temperature,
MAX([2014-07-13])[2014-07-13],
MAX([2014-07-14])[2014-07-14],
MAX([2014-07-15])[2014-07-15],
MAX([2014-07-16])[2014-07-16]
FROM
(
SELECT
Data,
Max_temp,
Min_Temp,
Sr_Temp,
Sr_Temp_work
FROM #temp
) SRC
PIVOT (
MAX(Min_Temp)
FOR Data IN ([2014-07-13],[2014-07-14],[2014-07-15],[2014-07-16])
) AS pvt
UNION ALL
SELECT
'Sr_Temp' Temperature,
MAX([2014-07-13])[2014-07-13],
MAX([2014-07-14])[2014-07-14],
MAX([2014-07-15])[2014-07-15],
MAX([2014-07-16])[2014-07-16]
FROM
(
SELECT
Data,
Max_temp,
Min_Temp,
Sr_Temp,
Sr_Temp_work
FROM #temp
) SRC
PIVOT (
MAX(Sr_Temp)
FOR Data IN ([2014-07-13],[2014-07-14],[2014-07-15],[2014-07-16])
) AS pvt
UNION ALL
SELECT
'Sr_Temp_work' Temperature,
MAX([2014-07-13])[2014-07-13],
MAX([2014-07-14])[2014-07-14],
MAX([2014-07-15])[2014-07-15],
MAX([2014-07-16])[2014-07-16]
FROM
(
SELECT
Data,
Max_temp,
Min_Temp,
Sr_Temp,
Sr_Temp_work
FROM #temp
) SRC
PIVOT (
MAX(Sr_Temp_work)
FOR Data IN ([2014-07-13],[2014-07-14],[2014-07-15],[2014-07-16])
) AS pvt
ON A DIFFERENT NOTE!
Dont use row by row..
DECLARE
#data_start Date = '2014-07-13',
#data_stop Date = '2014-07-19'
SELECT
[DateTime] Data
MAX(Value) Max_temp,
MIX(Value) Min_temp,
AVG(Value) Sr_Temp
AVG(case when CONVERT(TIME(7),DateTime) between '08:00:00.000' and '16:30:00.000' then Value else NULL end) Sr_Temp_work
FROM INSQL.Runtime.dbo.History
WHERE
TagName IN ('VariableName') and
wwRetrievalMode = 'Cyclic' AND
CONVERT(DATE, Datetime) between #data_start and #data_stop

Related

Data Truncated in SQL Server when assign json to variable

I want to generate JSON using T-SQL and stored it in a variable. When I assign the JSON to a NVARCHAR(MAX) the data is being truncated, But it is not being truncated if I directly use the select statement.
DECLARE #DateOne DATETIME, #DateTwo DATETIME,#DrillThroughData NVARCHAR(MAX)
SELECT #DateOne = '2016-01-01',#DateTwo = '2017-07-31'
CREATE TABLE #DrillThroughData
(
[Date] DATE
,TotalAmountIncome DECIMAL(18,4)
,TotalAmountRefunded DECIMAL(18,4)
,ProductCostIncome DECIMAL(18,4)
,ProductCostRefunded DECIMAL(18,4)
)
INSERT INTO #DrillThroughData
VALUES('2017-07-13',839.2000,-241.4000,0.0000,0.0000)
;WITH CTE AS
(
SELECT 1 SNo,CAST(CONVERT(NVARCHAR(6),#DateOne,112)+'01' AS DATE) AS StartDate
UNION ALL
SELECT SNo+1 SNo,DATEADD(DAY,1,StartDate ) StartDate
FROM CTE WHERE DATEADD(Day,1,StartDate ) <= #DateTwo
)
SELECT StartDate [Date],SNo
INTO #AllDays
FROM CTE
OPTION(MAXRECURSION 0)
-- Data not truncated here.
SELECT ad.[Date]
,FORMAT(ad.[Date],'yyyy-MMM') [Month]
,ISNULL(d.TotalAmountIncome,0) TotalAmountIncome
,ISNULL(d.TotalAmountRefunded,0) TotalAmountRefunded
,ISNULL(d.ProductCostIncome,0) ProductCostIncome
,ISNULL(d.ProductCostRefunded,0) ProductCostRefunded
FROM #DrillThroughData d
RIGHT JOIN #AllDays ad
ON d.[Date] = ad.Date
ORDER BY SNo
FOR JSON AUTO
SET #DrillThroughData = (SELECT ad.[Date]
,FORMAT(ad.[Date],'yyyy-MMM') [Month]
,ISNULL(d.TotalAmountIncome,0) TotalAmountIncome
,ISNULL(d.TotalAmountRefunded,0) TotalAmountRefunded
,ISNULL(d.ProductCostIncome,0) ProductCostIncome
,ISNULL(d.ProductCostRefunded,0) ProductCostRefunded
FROM #DrillThroughData d
RIGHT JOIN #AllDays ad
ON d.[Date] = ad.Date
ORDER BY SNo
FOR JSON AUTO)
-- Data is being Truncated even though the varaible is nvarchar(max)
SELECT #DrillThroughData
The actual length of the json when not truncated is 88441, but it is truncated at 13680.
Thanks in advance.

dynamic alias in sql server

I want query field with different alias in stored procedure
select COUNT(EmpCode) as CountEmp+#para
result shoud be
CountEmp1
45
CountEmp2
54
CountEmp1
76
Query loop in c# code:
select COUNT(EmpCode) where something = #something as CountEmp+#para
Approach without dynamic SQL:
--I create temp table for demonstration
DECLARE #some_table TABLE (
Something int,
EmpCode INT
)
INSERT INTO #some_table (Something, EmpCode)
VALUES (1, 10),(1, 22),(1, 12),(2, 12),(2, 30),(3, 65),(3, 15),(3, 11),(3, 5)
--Declare parameter we want to search
DECLARE #param int = 1
--Query
--In cte we select what we need based on parameter
;WITH cte AS (
SELECT 'CountEmp'+CAST(#param as nvarchar(10)) as SomeThing,
CAST(COUNT(EmpCode) as nvarchar(10)) as EmpCodeCount,
ROW_NUMBER() OVER (ORDER BY SomeThing ) as rn
FROM #some_table
WHERE SomeThing = #param
GROUP BY SomeThing
)
--And here comes UNION
SELECT SomeThing as Result
FROM (
SELECT SomeThing,rn
FROM cte
UNION ALL
SELECT EmpCodeCount ,rn
FROM cte
) as t
ORDER BY rn, SomeThing DESC
Output:
Result
------------------
CountEmp1
3
(2 row(s) affected)
Please try to make use of below code. Its working fine with SQL Server 2012.
IF OBJECT_ID ('temp..#Mytable') IS NOT NULL
CREATE TABLE #Mytable (ID INT IDENTITY (1,1),EmpCode INT)
DECLARE #max int ,#count int
SET #max =0;
DECLARE #str varchar(10)
INSERT #Mytable
(EmpCode)
VALUES
(10),
(45),
(35),
(63),
(56),
(65)
SET #count = (SELECT COUNT (ID) FROM #Mytable )
WHILE #count > #max
BEGIN
SET #max = #max+1
SET #str = CONVERT(varchar(10),#max)
EXEC('SELECT EmpCode AS Empcode'+#str+ ' FROM #Mytable WHERE ID = '+#str)
END

SQL Query - gather data based on date range - possible variable number of columns

please forgive my inexperience, I hope this isn't too dumb of a question, I'm stuck and have no where else to turn. I'll keep it to the point:
I'm trying to gather payroll data with the results like so:
The issue I have is the variable number of columns. I will be given a date range and are required to return an attendance record for each day in the given range, or a null value if no data is present. I'm using WebAPI as middle tier so I have the ability to perform further data manipulation to achieve this result.
My tables are as follows:
I can't be the first person who needs this done, any articles/posts or anything that would help me accomplish this? Even pseudo code would help; anything!
Thanks a million in advnace!
This is what I've been able to come up with but I'm not even sure if its doable:
-- convert date range into days of month
-- to ensure null values are included in data??
DECLARE #intFlag INT = 0;
DECLARE #numberOfDays INT = DATEDIFF(DAY, #startDate, #endDate);
DECLARE #TMP TABLE (DaysOfMonth date)
WHILE (#intFlag <= #numberOfDays)
BEGIN
INSERT INTO #TMP VALUES (DATEADD(DAY, #intFlag, #startDate));
SET #intFlag = #intFlag + 1
END
-- select days in given data range so c# app can build header row
-- would it help if I pivot this data?
SELECT
DaysOfMonth
FROM
#TMP
ORDER BY
DaysOfMonth
-- get a count for number of people
DECLARE #count INT = 0;
DECLARE #TMPPPL TABLE (Id int identity(1,0), PId Int)
INSERT INTO
#TMPPPL
SELECT
p.PersonId
FROM
dbo.People p
JOIN
dbo.UserTypes ut on p.UserType_UserTypeId = ut.UserTypeId and (ut.Code = 'caregiver' or ut.Code = 'director')
DECLARE #numberOfPeople INT = (SELECT COUNT(1) FROM #TMPPPL)
-- create and execute sproc to return row of data for each person
WHILE (#count <= #numberOfPeople)
BEGIN
-- STUCK HERE, This obviously won't work but what else can I do?
EXEC GetPersonAttendanceHours #personId, #startDate, #endDate;
SET #count = #count + 1
END
This was interesting. I think this will do what you're looking for. First test data:
CREATE TABLE people (PersonID int, Name varchar(30))
INSERT INTO people (PersonID, Name)
SELECT 1, 'Kelly'
UNION ALL SELECT 2, 'Dave'
UNION ALL SELECT 3, 'Mike'
CREATE TABLE attendances (PersonID int, SignIn datetime, SignOut datetime)
INSERT INTO attendances (PersonID, SignIn, SignOut)
SELECT 1, '1-Feb-2015 08:00', '1-Feb-2015 09:00'
UNION ALL SELECT 1, '1-Feb-2015 12:00', '1-Feb-2015 12:30'
UNION ALL SELECT 2, '2-Feb-2015 08:00', '2-Feb-2015 08:15'
UNION ALL SELECT 1, '3-Feb-2015 08:00', '3-Feb-2015 09:00'
UNION ALL SELECT 1, '4-Feb-2015 08:00', '4-Feb-2015 08:30'
UNION ALL SELECT 2, '4-Feb-2015 08:00', '4-Feb-2015 10:00'
UNION ALL SELECT 2, '6-Feb-2015 12:00', '6-Feb-2015 15:00'
UNION ALL SELECT 3, '6-Feb-2015 15:00', '6-Feb-2015 17:00'
UNION ALL SELECT 3, '8-Feb-2015 10:00', '8-Feb-2015 12:00'
Then a dynamic query:
DECLARE #startDate DATETIME='1-Feb-2015'
DECLARE #endDate DATETIME='9-Feb-2015'
DECLARE #numberOfDays INT = DATEDIFF(DAY, #startDate, #endDate)
declare #dayColumns TABLE (delta int, colName varchar(12))
-- Produce 1 row for each day in the report. Note that this is limited by the
-- number of objects in sysobjects (which is about 2000 so it's a high limit)
-- Each row contains a delta date offset, #startDate+delta gives each date to report
-- which is converted to a valid SQL column name in the format colYYYYMMDD
INSERT INTO #dayColumns (delta, colName)
SELECT delta, 'col'+CONVERT(varchar(12),DATEADD(day,delta,#startDate),112) as colName from (
select (ROW_NUMBER() OVER (ORDER BY sysobjects.id))-1 as delta FROM sysobjects
) daysAhead
WHERE delta<=#numberOfDays
-- Create a comma seperated list of columns to report
DECLARE #cols AS NVARCHAR(MAX)= ''
SELECT #cols=CASE WHEN #cols='' THEN #cols ELSE #cols+',' END + colName FROM #dayColumns ORDER BY delta
DECLARE #totalHours AS NVARCHAR(MAX)= ''
SELECT #totalHours=CASE WHEN #totalHours='' THEN '' ELSE #totalHours+' + ' END + 'ISNULL(' + colName +',0)' FROM #dayColumns ORDER BY delta
-- Produce a SQL statement which outputs a variable number of pivoted columns
DECLARE #query AS NVARCHAR(MAX)
SELECT #query=
'declare #days TABLE (reportDay date, colName varchar(12))
INSERT INTO #days (reportDay, colName)
SELECT DATEADD(day,Delta,'''+CONVERT(varchar(22),#startDate,121)+'''), ''col''+CONVERT(varchar(12),DATEADD(day,delta,'''+CONVERT(varchar(22),#startDate,121)+'''),112) as colName from (
select (ROW_NUMBER() OVER (ORDER BY sysobjects.id))-1 as Delta FROM sysobjects
) daysAhead
WHERE Delta<='+CAST(#numberOfDays as varchar(10))+'
SELECT p.Name, pivotedAttendance.*,'+#totalHours+' as totalHours FROM (
SELECT * FROM (
select p.PersonID, d.colName, CAST(DATEDIFF(MINUTE, a.SignIn, a.SignOut)/60.0 as decimal(5,1)) as hrsAttendance
from #days d
CROSS JOIN people p
LEFT OUTER JOIN attendances a ON a.PersonID=p.PersonID AND CAST(a.SignOut as DATE)=d.reportDay
) as s
PIVOT (
SUM(hrsAttendance) FOR colName in ('+#cols+')
) as pa
) as pivotedAttendance
INNER JOIN people p on p.PersonID=pivotedAttendance.PersonID'
-- Run the query
EXEC (#query)
Which produces data in a similar format to your example, with all of the days in the report range and a row for each person. From the above I see:
For presentation purposes you should be able to convert the column name to a display-able date (just parse the YYYYMMDD out of the column name). The date can't be used as the column name directly as it produces an invalid column name.
SQL Fiddle example here.
This is a variation on a theme that I've done in order to display schedules or attendance. I expect something similar should work with your report. Here is the beginning of your stored procedure:
DECLARE #iDay INT = 0;
DECLARE #countDays INT = DATEDIFF(DAY, #startDate, #endDate);
DECLARE #tempDates TABLE ([tempDate] DATE);
DECLARE #filterDates NVARCHAR;
WHILE (#iDay <= #countDays)
BEGIN
INSERT INTO #tempDates VALUES (DATEADD(DAY, #iDay, #startDate));
SET #iDay = #iDay + 1;
END;
SELECT #filterDates = STUFF(
(SELECT N''',''' + CONVERT(NVARCHAR, [tempDate], 103) FROM #tempDates FOR XML PATH('')),
1,
2,
''
);
You were on the right track with your suggestion. The next query gets your data before you PIVOT it.
SELECT [People].[Person_PersonID], [tempDates].[tempDate], [Attendances].[SignIn], [Attendances].[SignOut],
MIN([Attendances].[SignOut], DATEADD(DAY, 1, [tempDates].[tempDate]))
- MAX([Attendances].[SignIn], [tempDates].[tempDate]) * 24 AS [numHours]
FROM [People]
CROSS JOIN #tempDates [tempDates]
LEFT JOIN [Attendances]
ON (
([Attendances].[SignIn] < DATEADD(DAY, 1, [tempDates].[tempDate]))
AND ([Attendances].[SignOut] > [tempDates].[tempDate])
);
Once we're satisfied with the results of the previous query, we substitute it with a query using PIVOT, which should look something like this.
SELECT *
FROM (
SELECT [People].[PersonID], [tempDates].[tempDate], [Attendances].[SignIn], [Attendances].[SignOut],
MIN([Attendances].[SignOut], DATEADD(DAY, 1, [tempDates].[tempDate]))
- MAX([Attendances].[SignIn], [tempDates].[tempDate]) * 24 AS [numHours]
FROM [People]
CROSS JOIN #tempDates [tempDates]
LEFT JOIN [Attendances]
ON (
([Attendances].[SignIn] < DATEADD(DAY, 1, [tempDates].[tempDate]))
AND ([Attendances].[SignOut] > [tempDates].[tempDate])
)
) AS [DatedAttendance]
PIVOT (
SUM([numHours]) FOR ([tempDate] IN (#filterDates))
) AS [PivotAttendance]
ORDER BY [PersonID]

Consecutive streak of dates

Hopefully this isn't a dupe of another question, but I couldn't see it anywhere else - also this is a simplified version of another question I asked, hopefully to get me started on working out how to approach it.
I am looking to work out consecutive ranges of payments where there has been at least one payment in each month.
I have the following sample data
CREATE TABLE #data
(
Contact_reference NVARCHAR(55)
,Date_payment DATETIME
,Payment_value MONEY
)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2003-06-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2004-06-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2004-12-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-04-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-05-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-06-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-07-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-08-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-09-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-10-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-11-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-12-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-01-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-02-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-02-28',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-04-12',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-05-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-06-11',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-07-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-08-09',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-09-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-10-09',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-11-09',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-12-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2008-01-10',19.2308)
And what I would like to be able to do is to work out for each contact the ranges over which they gave consecutively (defined as giving at least once in every calendar month), the number of consecutive payments, the total value per range (and ideally if possible the gap between the current range and the end of the most recent one).
For the test data above my output would look like this:
CREATE TABLE #results
(
contact_reference NVARCHAR(55)
,Range_start DATETIME
,Range_end DATETIME
,Payments INT
,Value MONEY
,months_until_next_payment INT --works out the gap between the range_end date for a group and the range_start date for the next group
)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2003-06-08','2003-06-08',1,12.82,12)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2004-06-08','2004-06-08',1,12.82,6)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2004-12-08','2004-12-08',1,12.82,4)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2005-04-08','2006-02-28',12,153.843,2)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2006-04-12','2008-06-06',27,416.6673,NULL)
I've looked for answers using islands, or iterations but I quite frankly don't even know where to begin applying them to my question, so any help massively appreciated :)
Edit: I've added in the months_until_next_payment column. This would be more efficiently done in the application rather than with a self join however as SQL Server does not have any particularly satisfactory way of referencing next and previous rows.
;WITH base AS (
SELECT Contact_reference ,
Payment_value,
DATEPART(YEAR, Date_payment)*12 + DATEPART(MONTH, Date_payment) -
DENSE_RANK() OVER
(PARTITION BY Contact_reference
ORDER BY DATEPART(YEAR, Date_payment)*12 + DATEPART(MONTH, Date_payment)) AS G,
Date_payment
FROM #data
),
cte AS
(
SELECT
Contact_reference,
ROW_NUMBER() over (partition by Contact_reference
order by MIN(Date_payment)) RN,
MIN(Date_payment) Range_start,
MAX(Date_payment) Range_end,
COUNT(Payment_value) Payments,
SUM(Payment_value) Value
FROM base
GROUP BY Contact_reference, G
)
SELECT
c1.Contact_reference,
c1.Payments,
c1.Range_end,
c1.Range_start,
c1.Value,
DATEDIFF(month, c1.Range_end,c2.Range_start) months_until_next_payment
FROM cte c1
LEFT join cte c2 ON c1.Contact_reference=c2.Contact_reference and c2.RN = c1.RN+1
You can do it using cursor. Language like c#/java are better choice for this problem.
DECLARE #date DATETIME
DECLARE #nextDate DATETIME
DECLARE #rangeStart DATETIME
DECLARE #rangeEnd DATETIME
DECLARE #value decimal(18,2)
DECLARE #valueSum decimal(18,2)
DECLARE #count int
DECLARE #PaymentCursor CURSOR
SET #PaymentCursor = CURSOR FOR
SELECT Date_payment, Payment_value FROM #data
ORDER BY Date_payment
OPEN #PaymentCursor
FETCH NEXT FROM #PaymentCursor INTO #nextDate, #value
SET #date = #nextDate
SET #rangeStart = #nextDate
SET #valueSum = 0
SET #count = 0
WHILE (##FETCH_STATUS = 0)
BEGIN
FETCH NEXT FROM #PaymentCursor INTO #nextDate, #value
SET #count = #count + 1
SET #valueSum = #valueSum + #value
IF (DATEDIFF(mm, #date, #nextDate) > 1)
BEGIN
SELECT #rangeStart AS RangeStart, #date AS RangeEnd, #count AS Coount, #valueSum AS VALUE, DATEDIFF(mm, #date, #nextDate) AS months_until_next_payment
SET #valueSum = 0
SET #count = 0
SET #rangeStart = #nextDate
END
SET #date = #nextDate
END
SELECT #rangeStart AS RangeStart, #date AS RangeEnd, #count AS Coount, #valueSum AS VALUE, null AS months_until_next_payment
CLOSE #PaymentCursor
DEALLOCATE #PaymentCursor

How can i left out join these #temp (default data) and another table?

i try to generate a table (look TABLE 1) with the query(below).
CREATE TABLE #temp(
[VisitingCount] int,
[Time] nvarchar(50) )
DECLARE #DateNow DATETIME,#i int
SET #DateNow='00:00'
set #i=1;
while(#i<1440)
begin
set #DateNow=DATEADD(minute, 1, #DateNow)
insert into #temp ([VisitingCount], [Time]) values(0, right(left(convert(nvarchar, #DateNow, 121), 16), 5))
set #i=#i+1
end
select Count(VisitingCount) as VisitingCount,[Time]
from
#temp as Alltimes
left outer join
( SELECT Page,Date,[user],
dbo.fn_GetActivityLogArranger2(Date,'hour') as [Time]
FROM scr_SecuristLog
) scr_SecuristLog
on Alltimes.[Time] = scr_SecuristLog.[Time]
where
Date between '2009-04-30' and '2009-05-02'
and
[user] in
( select USERNAME
from scr_CustomerAuthorities
where customerID=Convert(varchar,4)
and ID=Convert(varchar,43)
)
group by [Time] order by [Time] asc
drop table #temp
i need this result(below). This codes about System entrance logs,
but there is a break lunch between 12:30 and 13:30.
So No entrance our system between 12:30 and 13:30.
if you draw log Graghic. You can see "M" character because of breaklunch gap
My Dream TABLE 1 Result:
Count---------Time---------
10------------10:30
22------------10:40
30------------10:50
44------------11:00
.
.
.
.
.
0-------------12:30
0-------------12:40
0-------------12:50
0-------------13:00
.
.
.
.
.
10-------------16:00
21-------------16:10
56-------------16:20
46-------------16:30
It is your where clause, what filters some time ranges out.
You need to set that clause for inner select:
select Count(VisitingCount) as VisitingCount,[Time]
from
#temp as Alltimes
left outer join
( SELECT Page,Date,[user],
dbo.fn_GetActivityLogArranger2(Date,'hour') as [Time]
FROM scr_SecuristLog
where Date between '2009-04-30' and '2009-05-02'
and
[user] in
( select USERNAME
from scr_CustomerAuthorities
where customerID=Convert(varchar,4)
and ID=Convert(varchar,43)
)
) scr_SecuristLog
on Alltimes.[Time] = scr_SecuristLog.[Time]
group by [Time] order by [Time] asc