How do I pivot with hour format(HH:HourNumber)? - sql-server-2008

I have OrderInfo table which contains OrderTime(date+time),OrderTrackDate(date),OrderTotal(sales amount) columns as shown in the following image.
1. Table1(Original Table)
Here is the code I have tried so far before pivoting.
SELECT CAST(DATEPART(DAY, OrderTime) as varchar)+'/'+ CAST(DATEPART(MONTH, OrderTime) as varchar)+'/'+CAST(DATEPART(year,OrderTime) as varchar) as daymonthyear,
ROUND(SUM(OrderTotal),2) AS Sales, COUNT(OrderTotal) AS Orders
,datepart(hour,OrderTime) as HH
FROM OrderInfo where OrderTime >= '5/24/2013' AND OrderTrackDate <='5/30/2013'
GROUP BY DATEPART(year, OrderTime),DATEPART(MONTH, OrderTime),DATEPART(day, OrderTime),datepart(hour,OrderTime)
Order By daymonthyear,HH
2. Table 2(Grouped according to Date,Hour from Table1)
How do I pivot dynamically and show sales amount per hour based on Table2?
DESIRED OUTPUT

First of all create a temp table to use it in 3 places - Select columns for pivot, Replace null with zero and inside pivot.
SELECT DISTINCT
SUM(ORDERTOTAL) OVER(PARTITION BY CAST(ORDERTIME AS DATE),DATEPART(HH,ORDERTIME)) [TOTAL],
CONVERT(varchar, CAST(ORDERTIME AS datetime), 103) [DATE],
DATEPART(HH,ORDERTIME) [HOUR],
'HH:'+CAST(DATEPART(HH,ORDERTIME) AS VARCHAR(3)) [HOURCOL]
INTO #NEWTABLE
FROM ORDERTBL
ORDER BY DATEPART(HH,ORDERTIME)
Now declare 2 variables to select columns for pivot and replace null with zero
DECLARE #cols NVARCHAR (MAX)
DECLARE #NullToZeroCols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + [HOURCOL] + ']',
'[' + [HOURCOL] + ']')
FROM (SELECT DISTINCT [HOUR],[HOURCOL] FROM #NEWTABLE) PV
ORDER BY [HOUR]
SET #NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+[HOURCOL]+'],0) AS ['+[HOURCOL]+']'
FROM(SELECT DISTINCT [HOUR],[HOURCOL] FROM #NEWTABLE GROUP BY [HOUR],[HOURCOL])TAB
ORDER BY [HOUR] FOR XML PATH('')),2,8000)
Now pivot the result
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT [DATE],' + #NullToZeroCols + ' FROM
(
SELECT [HOURCOL],[TOTAL], [DATE] FROM #NEWTABLE
) x
PIVOT
(
SUM([TOTAL])
FOR [HOURCOL] IN (' + #cols + ')
) p
;'
EXEC SP_EXECUTESQL #query
SQL FIDDLE

Related

Dynamic query in SSIS expression builder throwing an error expression cannot be evaluated

I am working on an example to write dynamic sql to pivot the data in ssis expression builder.It fails to evaluate the expression. Below is the dynamic query:
DECLARE #Cols as NVARCHAR(MAX)
DECLARE #SQL as NVARCHAR(MAX)
SELECT #Cols = COALESCE(#Cols + ', ','') + QUOTENAME(Name)
FROM
(
SELECT DISTINCT Category
FROM Product
) As t1
SET #SQL = 'SELECT *
FROM
(
SELECT ProductID,
Category,
Quantity
FROM Product
) as PivotData
PIVOT
(
COUNT(Quantity)
FOR Category IN (" + #Cols + ")
) AS PivotResult'
I think your double quotes around + #Cols needs to be single quotes, see below.
DECLARE #Cols as NVARCHAR(MAX)
DECLARE #SQL as NVARCHAR(MAX)
SELECT #Cols = COALESCE(#Cols + ', ','') + QUOTENAME(Name)
FROM
(
SELECT DISTINCT Category
FROM Product
) As t1
SET #SQL = 'SELECT *
FROM
(
SELECT ProductID,
Category,
Quantity
FROM Product
) as PivotData
PIVOT
(
COUNT(Quantity)
FOR Category IN (' + #Cols + ')
) AS PivotResult'

How can I get the max column value from every table in multiple schemas?

Is it possible to get the max value of a single column which exists in the majority of tables within several different schemas?
If this were one or two tables, I could easily use:
SELECT 'schema1.table1' as rowsource, category, max(date_used) max_date_used from schema1.table1 group by category
UNION ALL
SELECT 'schema1.table2' as rowsource, category, max(date_used) max_date_used from schema1.table2 group by category
UNION ALL
SELECT 'schema2.table3' as rowsource, category, max(date_used) max_date_used from schema2.table3 group by category
UNION ALL
SELECT 'schema3.table4' as rowsource, category, max(date_used) max_date_used from schema3.table4 group by category
However, I am looking at having to query nearly 300 tables across 3 different schemas.
TIA for any advice/insight!
You could try to store all your required table from informationSchema into a temp table, then use Dynamic SQL to go through each one of it. For example
DROP TABLE IF EXISTS #Temp
CREATE TABLE #temp ---identity column will be used to iterate
(
id INT IDENTITY,
TableName VARCHAR(50),
SchemaName VARCHAR(20)
)
INSERT INTO #temp
SELECT TABLE_NAME,TABLE_SCHEMA
FROM INFORMATION_SCHEMA.TABLES
-- choose your own results with where conditions
DECLARE #SQL VARCHAR(MAX) = ''
DECLARE #Count INT = 1
DECLARE #SchemaName VARCHAR(20)
DECLARE #Table VARCHAR(20)
WHILE #COUNT <= (SELECT COUNT(*) FROM #temp)
BEGIN
SELECT #SchemaName = SchemaName FROM #temp WHERE id = #Count
SELECT #table = TABLENAME FROM #temp WHERE id = #Count
SELECT #sql = #sql + 'SELECT category, max(date_used) max_date_used from ' + #SchemaName + '.' + #Table + ' group by category
UNION ALL '
SET #Count = #Count + 1
END
PRINT LEFT((#SQL),LEN(#SQL) - LEN('UNION ALL '))
After you check the printed result, change it to EXEC if you think that is correct for you.

Required Sum result in separate columns as per different elements in SQL

I am new in SQL basically i required Sum result in separate columns as per different elements.
Please find my table and required result in below image.
Please guide me with regards to SQL query which give me the required result.
You can use conditional aggregation:
select payment,
sum(case when product = 'A' then amount else 0 end) as a,
sum(case when product = 'B' then amount else 0 end) as b,
sum(case when product = 'C' then amount else 0 end) as c,
sum(case when product = 'D' then amount else 0 end) as d,
sum(amount) as total
from t
group by payment;
You can use PIVOT to get the desired result
SELECT * ,
[A] + [B] + [C] + [D] AS Total
FROM ( SELECT Payment, Product, Amount FROM Your_Table) tr
PIVOT( SUM(Amount) FOR Product IN ( [A], [B], [C], [D] ) ) p;
You can use dynamic SQL pivot query if your products are not limited with A,B,C and D
Here is a sample query for SQL Server
DECLARE #products nvarchar(max)
SELECT #products =
STUFF(
(
select distinct ',[' + product + ']'
from Payments
for xml path('')
),
1,1,'')
declare #sql nvarchar(max)
set #sql = '
SELECT
*
FROM (
SELECT
Payment AS '' '',
Product,
Amount
from Payments
) Data
PIVOT (
SUM(Amount)
FOR Product
IN (
' + #products + '
)
) PivotTable'
exec sp_executesql #sql
Below is sample data
IF OBJECT_ID('tempdb..#t')IS NOT NULL
DROp TABLE #t
;with cte (Payment,Product,Amount)
AS
(
SELECT 'Cash','A',1 UNION ALL
SELECT 'Credit','B',2 UNION ALL
SELECT 'Credit','C',3 UNION ALL
SELECT 'Cash','D',5 UNION ALL
SELECT 'Cash','A',6 UNION ALL
SELECT 'Credit','B',23 UNION ALL
SELECT 'Credit','C',7 UNION ALL
SELECT 'Cash','D',11 UNION ALL
SELECT 'Cash','A',12 UNION ALL
SELECT 'Credit','B',14 UNION ALL
SELECT 'Credit','C',16 UNION ALL
SELECT 'Cash','D',26
)
SELECT * INTO #t FROM cte
Using Dynamic Sql
DECLARE #DyColumn Nvarchar(max),
#Sql Nvarchar(max),
#ISNULLDyColumn Nvarchar(max),
#SumCol Nvarchar(max)
SELECT #DyColumn=STUFF((SELECT DISTINCT ', '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,1,'')
SELECT #ISNULLDyColumn=STUFF((SELECT DISTINCT ', '+'ISNULL('+QUOTENAME(Product)+',''0'')' +' AS '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,1,'')
SELECT #SumCol=STUFF((SELECT DISTINCT ' + '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,2,'')
SET #Sql='
SELECT *,('+#SumCol+') AS Total FROM
(
SELECT Payment,'+#ISNULLDyColumn+'
FROM
(
SELECT * FROM #t
)AS
SRC
PIVOT
(
SUM(AMOUNT) FOR Product IN ('+#DyColumn+')
) AS Pvt
)dt
'
PRINT #Sql
EXECUTE (#Sql)
Result
Payment A B C D Total
---------------------------------
Cash 19 0 0 42 61
Credit 0 39 26 0 65

ambiguous column name error sql server 2008

Hi all I have written the following Procedure to display the results as pivot as per the requirement
DECLARE #values AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #values = STUFF(
(
SELECT DISTINCT ',[' + ColumnName + ']'
FROM xTable
FOR xml path ('')
),1,1,'')
SET #query = 'SELECT viewName1.*, pValues.Code, ' + #values + ' FROM
(
SELECT Column1,Column2, Column3
FROM viewname
) aliasName
PIVOT
(
MAX(value)
FOR ColumnName in (' + #values + ')
) pValues INNER JOIN viewName1 ON pValues.Code = viewname.Code'
EXEC(#query)
But when the value and column names are same in my xTable and viewName1 I am getting that error how can I resolve this. I tried with alas but I am not getting the expected result so can some one help me.
Sample is I am having a ColumnName as TopBrand in my table xTable, this can be a value in my viewName1 like for X Column TopBrand can be a value.
I think you need to have a separate list for FOR and IN clauses and the former should include the alias:
DECLARE #valuesFor AS NVARCHAR(MAX),
#valuesIn AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #valuesFor = STUFF(
(
SELECT DISTINCT N',pValues.[' + ColumnName + ']'
FROM xTable
FOR xml path ('')
),1,1,'')
SELECT #valuesIn = STUFF(
(
SELECT DISTINCT N',[' + ColumnName + ']'
FROM xTable
FOR xml path ('')
),1,1,'')
SET #query = N'SELECT viewName1.*, pValues.Code, ' + #valuesFor + N' FROM
(
SELECT Column1,Column2, Column3
FROM viewname
) aliasName
PIVOT
(
MAX(value)
FOR ColumnName in (' + #valuesIn + N')
) pValues INNER JOIN viewName1 ON pValues.Code = viewname.Code'
EXEC(#query)

Convert String to comma separated values

I have a table as below
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB'
need output as below but without using any UDF.
Data String
------------
SQL S,Q,L
JOB J,O,B
Please help me on this
Sure you can :). You can make it shorter too...
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB';
With cte as
(
Select Data, Len(Data) DataLength, 1 level
From #t
Union All
Select Data, DataLength - 1, level + 1
From cte
Where DataLength > 1
),
cte2 as
(
Select Data, SUBSTRING(Data, DataLength, 1) DataLetter, level
From cte
),
cte3 as
(
Select Data,
(
SELECT DataLetter + ','
FROM cte2 c
Where c.Data = cte2.Data
Order By level desc
FOR XML PATH(''), TYPE
).value('.[1]', 'NVARCHAR(1000)') DataComa
From cte2
Group By Data
)
Select Data, substring(DataComa, 1, Len(DataComa) - 1) Data2
From cte3
Late to the party, but here's a slightly shorter version:
DECLARE #T TABLE(Data VARCHAR(MAX));
INSERT INTO #T VALUES('SQL'),('JOB'),('FLOOB');
;WITH n AS (SELECT TOP (SELECT MAX(LEN(Data)) FROM #T)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects
),
t AS (SELECT n, Data, Letter = SUBSTRING(t.Data, n.n, 1) FROM n
INNER JOIN #T AS t ON SUBSTRING(t.Data, n.n, 1) > ''
)
SELECT Data, STUFF((SELECT ',' + letter FROM t AS t2
WHERE t2.Data = t.Data ORDER BY t2.n FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'varchar(max)'), 1, 1, '')
FROM t GROUP BY Data;
Results:
FLOOB F,L,O,O,B
JOB J,O,B
SQL S,Q,L
It is very easy to do with UDF.
But If you want with out UDF, the only one way I can think of is
something like this
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB'
select replace(replace(replace(data,'S','S,'),'Q','Q,'),'L','L,') from #T
here you have to replace all the 26 characters with replace function. ie, 'A' with 'A,' 'B' with 'B,' .... 'Z' with 'Z,'
Using the same approach I used for Initcap function here http://beyondrelational.com/modules/2/blogs/70/posts/10901/tsql-initcap-function-convert-a-string-to-proper-case.aspx
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB'
select data,
upper(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(
' '+data ,
' a','a,'),' b','b,'),'c','c,'),'d','d,'),'e','e,'),'f','f,'),
' g','g,'),' h','h,'),'i','i,'),'j','j,'),'k','k,'),'l','l,'),
' m','m,'),' n','n,'),'o','o,'),'p','p,'),'q','q,'),'r','r,'),
' s','s,'),' t','t,'),'u','u,'),'v','v,'),'w','w,'),'x','x,'),
' y','y,'),' z','z,')) as splitted_data
from
#t