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.
Related
I have a data table with JSON documents in one column right now I iterate through each row to pivot out a(n) JSON array and flatten it out into another table. Is there a way to do this in a bulk action instead of an iteration process?
DECLARE #json varchar(max)
SET #json = (SELECT document
FROM dbo.MYJsonTable WITH (NOLOCK)
WHERE rawid = 4170159) -- unique identity value
SELECT
b.objectid,
b.staffRole,
b.statusName,
b.gwySync,
b.createdate,
b.rawid,
b.loaddate,
ROW_NUMBER() OVER (PARTITION BY objectid ORDER BY createdate) as row_num
FROM
(SELECT
JSON_Value(RePlace(#json,'$','') ,'$._id.oid') [objectid],
staffRole,
[statusName],
[gwySync],
DATEADD (hour, -6, DATEADD(MS, TRY_CONVERT(BIGINT, LEFT(Replace([$numberLong], '$', ''),10)), '1970-01-01 00:00:00')) [createdate],
4170159 [rawid],
GETDATE() [loaddate]
FROM
OPENJSON(#json, '$.patientJourneySteps')
WITH
(statusLog NVARCHAR(max) as JSON,
staffRole nvarchar(50) '$.staffRole') patientJourneySteps
OUTER APPLY
OPENJSON(patientJourneySteps.statusLog, '$')
WITH
(statusName NVARCHAR(15) '$.statusName',
gwySync nvarchar(20) '$.gwySync',
createdDate NVARCHAR(max) AS JSON) logs
OUTER APPLY
OPENJSON(logs.createdDate,'$')
WITH
([$date] NVARCHAR(max) AS JSON) DateJson
OUTER APPLY
OPENJSON(DateJson.[$date],'$')
WITH
([$numberLong] NVARCHAR(30))
) b
I have in my table rows with JSON same as a example:
json_data
[{"d":"2021-05-05T12:16:18.9175335","l":"temp12#cor.net","a":"test1","c":"Kom1"}]
[{"d":"2021-05-05T12:16:37.7258608","l":"temp12#cor.net","a":"test2","c":"Kom2"}]
[{"d":"2021-05-05T12:17:30.2390585","l":"temp12#cor.net","a":"test3","c":"Kom3"}]
I want to get data in table format. When is 1 row i don't have problem using:
DECLARE #JSONINPUT NVARCHAR(max)
SET #JSONINPUT = (select top 1 cast(json_data as varchar(max)) from mytable )
IF (ISJSON(#JSONINPUT) = 1)
BEGIN
SELECT * from OPENJSON(#JSONINPUT )
WITH (
[Kom] nvarchar(max) '$.c',
[Date] DATETIME2 '$.d',
[User] nvarchar(150) '$.a'
);
END
and i get:
Com
Date
User
Kom1
2021-05-05 12:16:18.9175335
test1
But I don't know how to get data from all rows.
Use CROSS APPLY with OPENJSON
SELECT j.Kom, j.[Date], j.[User]
FROM mytable
CROSS APPLY OPENJSON(json_data)
WITH (
[Kom] nvarchar(max) '$.c',
[Date] DATETIME2 '$.d',
[User] nvarchar(150) '$.a'
) AS j;
The syntax, as I mentioned, is no different:
SELECT OJ.Kom,
OJ.[Date],
OJ.[User]
FROM dbo.YourTable YT
CROSS APPLY OPENJSON(YT.JSONColumn)
WITH ([Kom] nvarchar(max) '$.c',
[Date] DATETIME2 '$.d',
[User] nvarchar(150) '$.a') OJ;
I have the following query, but it is not giving any regard to the in the p.created_by =#searchBy where clause, how to correct it so that the results would be filtered according #searchBy too.
ALTER PROC [dbo].[Rptcashcollectionouter] #branchId INT,
#searchBy INT,
#strDate DATETIME=NULL,
#endDate DATETIME=NULL
AS
BEGIN
SELECT DISTINCT p.created_on AS paid_date
FROM reading re
JOIN billing_gen bg ON re.id = bg.reading_id
JOIN customer_registration cr ON bg.account_number = cr.account_number
JOIN payment p ON bg.bill_number = p.bill_number
JOIN customer_category cc ON cr.customer_category_id = cc.id
WHERE p.created_by = #searchBy
AND ( ( #strDate IS NULL )
OR Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME) >=
Cast(Floor(Cast(#strDate AS FLOAT)) AS DATETIME) )
AND ( ( #endDate IS NULL )
OR Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME) <=
Cast(Floor(Cast(#endDate AS FLOAT)) AS DATETIME) )
AND cr.branch_id = #branchId
ORDER BY p.created_on ASC;
END;
Check the value inside your procedure as below.
SELECT #branchId, #searchBy, #strDate,#endDate
And, then try to run the SQL manually with the same value. Also, make sure you have data in your table for your criteria.
Also, what exactly you are trying here ?
Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME)
While executing procedure, make sure you are passing properly value.
Print out all values that are coming (Just for testing).
#searchBy INT is of integer type. But i think "p.created_by =#searchBy" is a type of datetime or date , so it may also conflicts here, or display wrong result. In below line. p.created_by is treating as a datetime or date and #searchby in integer.
WHERE p.created_by = #searchBy
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]
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