Using CTE with a dynamic pivot - sql-server-2008

I'm trying to use This question to perform a dynamic pivot, but I want to use a CTE to get the initial data.
My query looks like this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
WITH dataSet (coDate, TransactionDate, TotalBalance, TransDate, collected)
AS
( *SELECT STATEMENT )
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.category)
FROM dataSet c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT coDate, ' + #cols + ' from
(
select coDate
, TotalBalance
, collected
, TransDate
from dataSet
) x
pivot
(
SUM(collected)
for category in (' + #cols + ')
) p '
execute(#query)
And the error SQL gives me is Incorrect syntax near the keyword 'SET'. I did try adding a semicolon and go as well as a comma before the SET statement, but this the first time I've used PIVOT so I'm not sure how CTE interacts with it.

Related

Omitting Scientific Notation in Numeric columns when working with Dynamic SQL returning JSON

The below dynamic query returns the output of the numeric columns in Scientific notation.
DECLARE #Cols VARCHAR(MAX) = (SELECT STUFF((
SELECT ',' +'['+ Description + ']' FROM #PermittedColumnIDs
DECLARE #Query NVARCHAR(MAX) = 'SELECT TOP 1000 '+ #Cols +' FROM ' + (SELECT ViewName FROM
#DynamicQueryProps) + ' FOR JSON AUTO';
EXECUTE sp_executesql #Query
JSON output
Tabular output
As above mentioned, tabular view returns the AWP value properly and JSON view returns it with the scientific notation. How to get the JSON AWP column without Sc. notation.
Please note that
It needs to preserve the numeric value as numeric without converting it to a string in the JSON result.
Cannot change the format of individual columns since columns are dynamic.
It's too long for a comment, so I post this as an answer. I'm able to find only these explanations in the documentation about how FOR JSON converts SQL Server data types to JSON types. So, as a possible workaround, you may try to convert the float columns to numeric using information from system catalog views (I assume, that the SELECT is against a view).
DECLARE #cols varchar(MAX) = STUFF(
(
SELECT
', ' +
CASE
WHEN t.[name] = 'float' THEN 'CONVERT(numeric(10, 2), [' + p.[description] + ']) AS [' + p.[description] + N'] '
ELSE p.[description]
END
FROM sys.columns c
JOIN sys.views v ON c.object_id = v.object_id
JOIN sys.schemas s ON v.schema_id = s.schema_id
JOIN sys.types t ON c.system_type_id = t.system_type_id
JOIN #PermittedColumnIDs p ON p.[description] = c.[name]
WHERE v.[name] = (SELECT ViewName FROM #DynamicQueryProps) AND s.[name] = 'dbo'
FOR XML PATH(''), TYPE
).value('.', 'varchar(max)'), 1, 1, ''
)
DECLARE #query nvarchar(max)
SET #query =
N' SELECT TOP 1000 '+ #Cols +
N' FROM [' + (SELECT ViewName FROM #DynamicQueryProps) + ']' +
N' FOR JSON AUTO';
EXECUTE sp_executesql #query

Convert dynamic SQL Server Pivot to MySQL

I have written below stored procedure in sql server
CREATE PROCEDURE usp_getQuantityBilling()
-- VARIABLE --
DECLARE #cols AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
select #cols = group_concat(name)
from visit_groups where arm_id='377';
set #query = 'SELECT id, service, rate, subjectcount, armDetailsId, totalHours,'
+ #cols + ' FROM
(
select protocols.id, arms.name, visit_groups.name as visitGroup, services.name as serviceName, visits.quantity,
line_items_visits.subject_count
from protocols,arms,visit_groups,visits,line_items,line_items_visits,services
where protocols.id = arms.protocol_id
and visit_groups.arm_id = arms.id
and visits.visit_group_id = visit_groups.id
and line_items_visits.arm_id = arms.id
and visits.line_items_visit_id = line_items_visits.id
and line_items_visits.line_item_id = line_items.id
and services.id = line_items.service_id
and protocols.id = ''' + 591 + '''
) x
pivot
(
max(isActive)
for visitName in (' + #cols + ')
) p';
execute (#query)
I am trying to convert this into mysql server but I am not sure how to declare the variables in mysql stored proc and how to run all these quesry together where result generated by previous query can be used in next query.
Also below query:
select #cols = group_concat(name)
from visit_groups where arm_id='377';
is giving error
Error Code: 1267. Illegal mix of collations (utf8_general_ci,IMPLICIT)
and (utf8_unicode_ci,IMPLICIT) for operation '=' 0.000 sec
so i looked for the solution and made it like this
select #cols = group_concat(name) COLLATE utf8_unicode_ci from visit_groups
where arm_id='377';
Now I am getting result as 0 with a column name #cols = group_concat(name) COLLATE utf8_unicode_ci , but the result should actually look like visit1, visit 2 because that is what I am getting in sql server.
Edit
SELECT id, name, visitGroup, serviceName, quantity, subject_count,'
+ [Visit 1],[Visit 2] + ' FROM
(
select protocols.id, arms.name, visit_groups.name as visitGroup, services.name as serviceName,
visits.quantity,
line_items_visits.subject_count
from protocols,arms,visit_groups,visits,line_items,line_items_visits,services
where protocols.id = arms.protocol_id
and visit_groups.arm_id = arms.id
and visits.visit_group_id = visit_groups.id
and line_items_visits.arm_id = arms.id
and visits.line_items_visit_id = line_items_visits.id
and line_items_visits.line_item_id = line_items.id
and services.id = line_items.service_id
and protocols.id = ''' + 591 + '''
) x
pivot
(
max(isActive)
for visitName in (' + [Visit 1],[Visit 2] + ')
) p'
main issue is running this query, it shows error in mysql that pivot is used at wrong position but in sql it works fine. Anyway to turn this query into mysql pivot query.
Note: this Visit 1 and Visit 2 I am generating dynamically but just for this solution I copied here manually.

Getting bad format on float values when exporting query to html table

I need some help on this. I use this code to export SQL queries to html tables (got code from Convert a SQL query result table to an HTML table for email)
-- Description: Turns a query into a formatted HTML table. Useful for emails.
-- Any ORDER BY clause needs to be passed in the separate ORDER BY parameter.
-- =============================================
CREATE PROC [dbo].[spQueryToHtmlTable]
(
#query nvarchar(MAX), --A query to turn into HTML format. It should not include an ORDER BY clause.
#orderBy nvarchar(MAX) = NULL, --An optional ORDER BY clause. It should contain the words 'ORDER BY'.
#html nvarchar(MAX) = NULL OUTPUT --The HTML output of the procedure.
)
AS
BEGIN
SET NOCOUNT ON;
IF #orderBy IS NULL BEGIN
SET #orderBy = ''
END
SET #orderBy = REPLACE(#orderBy, '''', '''''');
DECLARE #realQuery nvarchar(MAX) = '
DECLARE #headerRow nvarchar(MAX);
DECLARE #cols nvarchar(MAX);
SELECT * INTO #dynSql FROM (' + #query + ') sub;
SELECT #cols = COALESCE(#cols + '', '''''''', '', '''') + ''['' + name + ''] AS ''''td''''''
FROM tempdb.sys.columns
WHERE object_id = object_id(''tempdb..#dynSql'')
ORDER BY column_id;
SET #cols = ''SET #html = CAST(( SELECT '' + #cols + '' FROM #dynSql ' + #orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL) AS nvarchar(max))''
EXEC sys.sp_executesql #cols, N''#html nvarchar(MAX) OUTPUT'', #html=#html OUTPUT
SELECT #headerRow = COALESCE(#headerRow + '''', '''') + ''<th>'' + name + ''</th>''
FROM tempdb.sys.columns
WHERE object_id = object_id(''tempdb..#dynSql'')
ORDER BY column_id;
SET #headerRow = ''<tr>'' + #headerRow + ''</tr>'';
SET #html = ''<table border="1">'' + #headerRow + #html + ''</table>'';
';
EXEC sys.sp_executesql #realQuery, N'#html nvarchar(MAX) OUTPUT', #html=#html OUTPUT
END
GO
The code works perfect, but has one problem formatting float values.
For example:
SELECT Name, Weight FROM Products
The query returns something like this when executed from Management Studio:
Name1 | 1073,822
Name2 | 179,554
When I use the stored procedure to export this to html table, then I get the results like this:
Name1 | 1.073822000000000e+003
Name2 | 1.795540000000000e+002
Don't know exactly how to change the stored procedure to adapt it in order to avoid this wrong formatting on float values.
Any help on this would be appreciated.
you are using cast to show the values in the html-table:
SET #cols = ''SET #html = CAST(( SELECT '' + #cols + '' FROM #dynSql ' + #orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL) AS nvarchar(max))''
MS-Help tells you more, but basically this is the automatic behavior of cast with a float value.
You should try to already convert your float-fields to the desired format in the query you pass, using the STR() function, see str function description
Many thanks for your reply
EDIT: If I take out the casting to varchar(max), the result seems to be the same.
But I've just tried to do something like this:
SELECT Name, CAST(Weight AS varchar(max)) FROM Products
And I still can see the right formatted values:
Name1 | 1073.82
Name2 | 179.554
Otherwise, I use this SP to be called from many sites and processes. Is not possible to check every case and try to cast the float fields.
I need a solution to be implemented at the SP level.
I've tried to use the STR() function, so changed the line:
SET #cols = ''SET #html = CAST(( SELECT '' + #cols + '' FROM #dynSql ' + #orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL) AS nvarchar(max))''
To
SET #cols = ''SET #html = STR(( SELECT '' + #cols + '' FROM #dynSql ' + #orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL))''
But then I'm getting the error: Error converting data type nvarchar to float.
Not sure if this is what you mentioned.
Would be a way to check the field type in the SP, and use a different casting for the float cases?
How could I do it?
Regards,

Find minimum and maximum column value of a common column across all tables in a SQL Server 2008 database

I am examining a third party SQL Server 2008 database. In this database, there are 2 columns CREATED_DATETIME and UPDATED_DATETIME, which are present in majority of the tables, but probably not all.
I want to find the minimum and maximum value of these 2 columns across all tables in the database which have these 2 columns. That will give me a fair idea that the data in the database is from which period to which period.
How can I write such a query?
Something like the following should work
DECLARE #C1 AS CURSOR,
#TABLE_SCHEMA SYSNAME,
#TABLE_NAME SYSNAME,
#HasCreated BIT,
#HasUpdated BIT,
#MaxDate DATETIME,
#MinDate DATETIME,
#SQL NVARCHAR(MAX)
SET #C1 = CURSOR FAST_FORWARD FOR
SELECT TABLE_SCHEMA,
TABLE_NAME,
COUNT(CASE
WHEN COLUMN_NAME = 'CREATED_DATETIME' THEN 1
END) AS HasCreated,
COUNT(CASE
WHEN COLUMN_NAME = 'UPDATED_DATETIME' THEN 1
END) AS HasUpdated
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN ( 'CREATED_DATETIME', 'UPDATED_DATETIME' )
GROUP BY TABLE_SCHEMA,
TABLE_NAME
OPEN #C1;
FETCH NEXT FROM #C1 INTO #TABLE_SCHEMA , #TABLE_NAME , #HasCreated , #HasUpdated ;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = N'
SELECT #MaxDate = MAX(D),
#MinDate = MIN(D)
FROM ' + QUOTENAME(#TABLE_SCHEMA) + '.' + QUOTENAME(#TABLE_NAME) + N'
CROSS APPLY (VALUES ' +
CASE WHEN #HasCreated = 1 THEN N'(CREATED_DATETIME),' ELSE '' END +
CASE WHEN #HasUpdated = 1 THEN N'(UPDATED_DATETIME),' ELSE '' END + N'
(#MaxDate),
(#MinDate)) V(D)
'
EXEC sp_executesql
#SQL,
N'#MaxDate datetime OUTPUT, #MinDate datetime OUTPUT',
#MaxDate = #MaxDate OUTPUT,
#MinDate = #MinDate OUTPUT
FETCH NEXT FROM #C1 INTO #TABLE_SCHEMA , #TABLE_NAME , #HasCreated , #HasUpdated ;
END
SELECT #MaxDate AS [#MaxDate], #MinDate AS [#MinDate]
select MIN(CREATED_DATETIME) MinCREATED_DATETIME_Table1, MAX(CREATED_DATETIME) MaxCREATED_DATETIME_Table1, MIN(CREATED_DATETIME) MinCREATED_DATETIME_Table2, MAX(CREATED_DATETIME) MaxCREATED_DATETIME_Table2 from Table1, Table2
Run this script in SSMS (CTrl+T=text results, F5=execute query):
SET NOCOUNT ON;
SELECT 'SELECT MIN('
+ QUOTENAME(c.COLUMN_NAME)
+ ') AS '
+ QUOTENAME('Min '+c.TABLE_NAME+'.'+c.COLUMN_NAME)
+ ', MAX('
+ QUOTENAME(c.COLUMN_NAME)
+ ') AS '
+ QUOTENAME('Max_'+c.TABLE_NAME+'.'+c.COLUMN_NAME)
+ CHAR(13)
+ 'FROM ' + QUOTENAME(c.TABLE_SCHEMA)+'.'+QUOTENAME(c.TABLE_NAME)
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.COLUMN_NAME IN ('CREATED_DATETIME', 'UPDATED_DATETIME')
ORDER BY c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME;
SET NOCOUNT OFF;
It will generate another script. Execute generated script.
Example (generated script for master database and all tables with low column name > WHERE c.COLUMN_NAME IN (N'low')):
SELECT MIN([low]) AS [Min spt_fallback_dev.low], MAX([low]) AS [Max_spt_fallback_dev.low]
FROM [dbo].[spt_fallback_dev]
SELECT MIN([low]) AS [Min spt_values.low], MAX([low]) AS [Max_spt_values.low]
FROM [dbo].[spt_values]
Run the script mentioned in the link below. You will have to slightly alter as per your requirements.
SCRIPT to Search every Table and Field

write a TRANSFORM statement in Sql Server

I am migrating a web application backend from Access to MSSQL, however I was not able o reproduce the following Query in MSSQL, any ideas?
TRANSFORM First(FollowUp.FUData) AS FirstOfFUData
SELECT FollowUp.MRN
FROM FollowUp
GROUP BY FollowUp.MRN
PIVOT FollowUp.FU;
please note that this query converts data from the EAV table Followup to a normal table.
This is the design of the table Followup:
In SQL Server you can use the PIVOT function and your query would be set up this way:
select MRN, Value1, Value2
from
(
select MRN, FUData, FU
from FollowUp
) src
pivot
(
max(FUData)
for FU in (Value1, Value2)
) piv
Where you would replace the Value1, Value2, etc with any of the values that you items that should now be columns.
SQL Server 2008, does not have a FIRST() function so you will have to use another aggregate function or query the data in such a manner to return the the first record for each item in FU.
Another way to write this is using an aggregate function with a CASE statement:
select MRN,
max(case when FU = 'value1' then FUData else null end) Value1,
max(case when FU = 'value2' then FUData else null end) Value2
from FollowUp
group by MRN
The above versions will work great if you have a known number of FU values to transform into columns, but if you do not then you will need to use dynamic SQL similar to this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(FU)
from FollowUp
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT MRN,' + #cols + ' from
(
select MRN, FUData, FU
from FollowUp
) x
pivot
(
max(FUData)
for FU in (' + #cols + ')
) p '
execute(#query)