Dynamic Gridview with Pivot Table - sql-server

I am currently creating a gridview that has dynamic columns.
I have successfully created this from querying the log hours for every task per date on a specific sprint. The logged dates becomes the column and the task and logged hours become rows. With both vertical and horizontal totals.
On this gridview, you can manually edit the logged hours and it will be saved to the database.
The problem now is the design changes.
What I need to do is just list the sprint duration dates for columns and task on the first column even if there are still no logged hour on that task or date.
Any help will be appreciated. Thanks.
here is the stored procedure for this pivoted table
USE [JiraAutomation]
GO
/****** Object: StoredProcedure [dbo].[logs] Script Date: 4/12/2016 7:00:09 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[logs]
#username nvarchar(30),
#sprintId nvarchar(30)
AS
/* COLUMNS HEADERS */
Declare
#cols as NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(log_date)
from tbl_log join tbl_task on tbl_task.task_id = tbl_log.task_id
where tbl_log.username = #username
and tbl_log.sprint_id = #sprintId
group by log_date
order by log_date
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
DECLARE #horiz_total nvarchar(MAX)
SELECT #horiz_total = stuff((
SELECT '+isnull(' + quotename(log_date) + ',0)'
FROM tbl_log
join tbl_task on tbl_task.task_id = tbl_log.task_id
where tbl_log.username = #username
and tbl_log.sprint_id = #sprintId
GROUP BY log_date
ORDER BY log_date
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
DECLARE #vert_total nvarchar(MAX)
SELECT #vert_total = stuff((
SELECT ',sum(' + quotename(log_date) + ')'
FROM tbl_log
join tbl_task on tbl_task.task_id = tbl_log.task_id
where tbl_log.username = #username
and tbl_log.sprint_id = #sprintId
GROUP BY log_date
ORDER BY log_date
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
DECLARE #isnulls nvarchar(MAX)
SELECT #isnulls = stuff((
SELECT ',isnull(' + quotename(log_date) + ',0) as '+quotename(log_date)
FROM tbl_log
GROUP BY log_date
ORDER BY log_date
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
DECLARE #query nvarchar(MAX)
SET #query = 'select task_description as TASK,' + #cols + ',' + #horiz_total + ' as Total
into #tmp_result
from (select task_description, log_date, log_hours from tbl_log join tbl_task on tbl_task.task_id = tbl_log.task_id
where tbl_log.username = '''+#username+'''
and tbl_log.sprint_id = '''+#sprintId+'''
) x
pivot (sum(log_hours) for log_date in (' + #cols + ')) p
select *
from #tmp_result
union all
SELECT '''','+#vert_total +',
ISNULL (SUM([Total]),0) FROM #tmp_result
DROP TABLE #tmp_result'
-- PRINT 'Pivot Query '+#FinalQuery
EXECUTE(#query)

If I understand the issue correctly, then the issue is with the type of join in your query in the #query variable
'select task_description as TASK,' + #cols + ',' + #horiz_total + ' as Total
into #tmp_result
from (select task_description, log_date, log_hours from tbl_log join tbl_task on tbl_task.task_id = tbl_log.task_id
where tbl_log.username = '''+#username+'''
and tbl_log.sprint_id = '''+#sprintId+'''
The JOIN is exclusive, so if there is no tasks it will exclude the records in the tbl_log.
To display the values from tbl_log regardless of havng corresponding records in tbl_task the join should be changed to inclusive, in your case this should be a LEFT OUTER JOIN
so the code should look like
'select task_description as TASK,' + #cols + ',' + #horiz_total + ' as Total
into #tmp_result
from (select task_description, log_date, log_hours from tbl_log LEFT OUTER JOIN tbl_task on tbl_task.task_id = tbl_log.task_id
where tbl_log.username = '''+#username+'''
and tbl_log.sprint_id = '''+#sprintId+'''
You can omit the OUTER from LEFT OUTER JOIN
here is a link to nice explanation of different types of joins
SQL JOIN and different types of JOINs
I hope this helps.

Related

SQL Server : dynamically select column based on another select column

I would like to write a query that returns two columns. The first column would be all of the column names of an existing table (ImportTable) sorted alphabetically, and the second column would be a sample row from that table (ImportTable) showing a potential value for one of those columns.
This is the pseudo code I have so far:
select
c.name as 'Column Name',
(select top(1) ImportTable."c.name"
from Database.dbo.[ImportTable] ImportTable) as 'Sample Column Value'
from
Database.sys.columns c
inner join
Database.sys.objects o on o.object_id = c.object_id
where
o.name = 'ImportTable'
order by
c.name asc
I don't know how to dynamically select the column ImportTable."c.name" based on the value of the column name. I'm not even sure what to search for that.
You need to create a dynamic unpivot statement and execute it.
Try not to get confused about what is the static and what the dynamic parts.
DECLARE #sql nvarchar(max) = N'
SELECT v.*
FROM (
SELECT TOP (1) *
FROM ' + QUOTENAME(#tablename) + N'
ORDER BY CHECKSUM(NEWID())
) t
CROSS APPLY (VALUES
' +
(
SELECT STRING_AGG(CAST(
N'(' + QUOTENAME(c.name, '''') + N', CAST(t.' + QUOTENAME(c.name) + N' AS sql_variant))'
AS nvarchar(max)), N',
') WITHIN GROUP (ORDER BY c.name ASC)
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(#tablename)
) +
N'
) AS v(columnName, columnValue);
';
PRINT #sql; -- for testing
EXEC sp_executesql #sql;
If you are unfortunate enough to still be on a version not supporting STRING_AGG, you can use FOR XML instead for that part:
-------
CROSS APPLY (VALUES
' +
STUFF(
(
SELECT N',
(' + QUOTENAME(c.name, '''') + N', CAST(t.' + QUOTENAME(c.name) + N' AS sql_variant))'
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(#tablename)
ORDER BY c.name ASC
FOR XML PATH(''), TYPE
).value('text()[1]', 'nvarchar(max)'), 1, 2, '') +
N'
) AS v(columnName, columnValue);
';
--------
With a little dynamic SQL, you can get this done with just a series of UNION selects. This doesn't require string_agg or any recent SQL feature.
declare #table sysname = N'schema.YourTableName';
-- Begin with a CTE to select 1 row at random:
declare #stmt nvarchar(max) = N'with cte as (select top(1)* from ' + #table + ' order by newid())';
-- Create string of UNION selects:
select #stmt = #stmt
+ 'select '''
+ name
+ ''' as ColumnName, cast('
+ name
+ ' as varchar(max)) as SampleValue from cte union '
from sys.columns
where object_id = object_id(#table)
-- Remove the trailing "union"
set #stmt = left(#stmt,len(#stmt)-5);
-- Add the ORDER
set #stmt = #stmt + ' order by ColumnName';
-- Execute the query:
exec sp_executesql #stmt = #stmt;

Copy oldtable to newTable base on pivot query result?

I have a pivot query from pivoted table*(a dynamic columns)*, my problem is I want to copy/clone the pivot result into new_table. Which is I don't know how to do it,
Query:
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT','+QUOTENAME(c.ReportedDate)
FROM dbo.Activity c FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '');
SELECT #query = 'SELECT * FROM (SELECT b.Description, CONVERT(VARCHAR(10), reportedDate, 120) as reportedDate,Status
FROM Activity left join ActivityType b on b.activityTypeId = Activity.ActivityTypeId )
AS t PIVOT ( COUNT(reportedDate) FOR reportedDate IN( ' + #cols + ' )' + ') AS p ;'
EXECUTE (#query);
How to achieve my expectations to get the same result from pivotTable to new_table with the same data result?
You can use a table (or a global temporary table) to store data via select into, so you will able to have access on it.
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT','+QUOTENAME(c.ReportedDate)
FROM dbo.Activity c FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '');
SELECT #query = 'SELECT * into ##results FROM (SELECT b.Description, CONVERT(VARCHAR(10), reportedDate, 120) as reportedDate,Status
FROM Activity left join ActivityType b on b.activityTypeId = Activity.ActivityTypeId )
AS t PIVOT ( COUNT(reportedDate) FOR reportedDate IN( ' + #cols + ' )' + ') AS p ;'
EXECUTE (#query);
SELECT * FROM ##results

sp_executesql or execute without variables

Id like to execute this query on sql server 2012 without using variables:
DECLARE #query VARCHAR(4000)
set #query= concat('select * from customer where id in (',
(select id from customer where comid=1 and code='30.00.0000'),
') order by code')
execute #query
So I tried this:
sp_executesql N'
select concat(''select * from customer where id in ('',
(select id from customer where comid=1 and code=''30.00.0000''),
'') order by code'')'
with no effect as it produces the query instead of returning the values.
Above version is cropped. This is whole script:
DECLARE #query VARCHAR(4000)`
DECLARE #years VARCHAR(2000)`
SELECT #years = STUFF((
SELECT DISTINCT
'],[' + ltrim(str(etos))
FROM
(
select c.code , year(f.ftrdate) as etos , sum((it.outputvalmode-it.inputvalmode)*st.netlinevalue) as katharh
from fintrade f left join itemtrans it on it.ftrid=f.id
left join material m on m.id=it.iteid
left join storetradelines st on it.stlid=st.id
left join customer c on c.id=f.cusid
where m.code like '73.00.901%' and m.comid=1
group by c.code , year(f.ftrdate)
)a
ORDER BY '],[' + ltrim(str(etos))
FOR XML PATH('')), 1, 2, '') + ']'
SET #query =
'SELECT * FROM
(
select c.code , year(f.ftrdate) as etos , sum((it.outputvalmode-it.inputvalmode)*st.netlinevalue) as katharh
from fintrade f left join itemtrans it on it.ftrid=f.id
left join material m on m.id=it.iteid
left join storetradelines st on it.stlid=st.id
left join customer c on c.id=f.cusid
where m.code like ''73.00.901%'' and m.comid=1
group by c.code , year(f.ftrdate)
) AS t
PIVOT (MAX(katharh) FOR etos IN (' + #years + ')) AS pvt'`
print (#query)
execute (#query)
Taking your code
sp_executesql N'
select concat(''select * from sys.objects object_id id in ('',
(select object_id from sys.objects where object_id=1 and object_id=''30000000''),
'') order by object_id'')'
and removing one level of nesting (the sp_executesql) we get
select concat('select * from sys.objects object_id id in (',
(select object_id from sys.objects where object_id=1 and object_id='30000000'),
') order by object_id')
which of course outputs
select * from sys.objects object_id id in () order by object_id
as you observed.
I think you should do:
sp_executesql #query

Using a Temp Table in a Dynamic Pivot

I am trying to use a temp table inside of a dynamic pivot query. I have read that the procedure will not work because the temp table is outside of the scope even though it is a global table. This is strange to me because it works in sql fiddle but not in SQL Server 2012. How can I edit my query so that it gives me an output other than (xxx row(s) affected)?
Here is my query:
SELECT cc.CaseCaseId AS CaseId, cc.Label AS CaseName, rce.EcoDate, cc.OperatorName, cc.State, cc.County, ei.IROR, rce.NDCash
into ##Temp2
FROM PhdRpt.ReportCaseList_542 AS rcl INNER JOIN
CaseCases AS cc ON rcl.CaseCaseId = cc.CaseCaseId INNER JOIN
PhdRpt.RptCaseEco_542 AS rce ON rcl.ReportRunCaseId = rce.ReportRunCaseId INNER JOIN
PhdRpt.EcoIndicators_542 AS ei ON rcl.ReportRunCaseId = ei.ReportRunCaseId
DECLARE #colsPivot AS NVARCHAR(MAX),
#colsUnpivot as NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsPivot = STUFF((SELECT distinct ',' + QUOTENAME(EcoDate)
from ##Temp2
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsUnpivot = stuff((select ','+quotename(C.name)
from sys.columns as C
where C.object_id = object_id('##Temp2') and
C.name LIKE 'NDCash%'
for xml path('')), 1, 1, '')
set #query
= 'select *
from
(
select cc.CaseCaseId AS CaseId, cc.Label AS CaseName, rce.EcoDate, cc.OperatorName, cc.State, cc.County, ei.IROR, val, col
FROM ##Temp2
unpivot
(
val
for col in ('+ #colsunpivot +')
) u
) x1
pivot
(
max(val)
for EcoDate in ('+ #colspivot +')
) p'
exec(#query)
Drop table ##Temp2
Here is the table structure:
CaseId EcoDate NDCash
2 2003-01-01 26.6384943638238
2 2004-01-01 23.9534867373416
2 2005-01-01 25.9197356158675
2 2006-01-01 25.3280437702064
2 2007-01-01 24.9828609298022
2 2008-01-01 26.4019321789285
2 2009-01-01 26.6384943638238
2 2010-01-01 24.0660715481002
2 2011-01-01 26.6384943638238
2 2012-01-01 22.5718444448345
2 2013-01-01 26.6384943638238
Unless I am missing something, you don't need to use UNPIVOT for this and you don't need to use a temp table, just query the data directly. It looks like your current query is only unpivoting one column which is not needed. You use unpivot to convert multiple columns into multiple rows.
You should be able to use:
DECLARE #colsPivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsPivot = STUFF((SELECT ',' + QUOTENAME(rce.EcoDate)
from PhdRpt.RptCaseEco_542 AS rce
group by rce.EcoDate
order by rce.EcoDate
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select *
from
(
SELECT cc.CaseCaseId AS CaseId,
cc.Label AS CaseName,
rce.EcoDate,
cc.OperatorName,
cc.State,
cc.County,
ei.IROR,
rce.NDCash
FROM PhdRpt.ReportCaseList_542 AS rcl
INNER JOIN CaseCases AS cc
ON rcl.CaseCaseId = cc.CaseCaseId
INNER JOIN PhdRpt.RptCaseEco_542 AS rce
ON rcl.ReportRunCaseId = rce.ReportRunCaseId
INNER JOIN PhdRpt.EcoIndicators_542 AS ei
ON rcl.ReportRunCaseId = ei.ReportRunCaseId
) x1
pivot
(
max(NDCash)
for EcoDate in ('+ #colspivot +')
) p'
exec(#query)
change the exec(#query) to sp_executeSQl #query.
exec(#query) will not execute in the current context, but where as the sp_executeSQL will execute with the current context that includes the temporary tables as well.

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries

my stored procedeur like this:
alter PROCEDURE [dbo].[ParkingDeatailsReportnewstack]
#startdate NVARCHAR(100),
#enddate NVARCHAR(100)AS
BEGIN
DECLARE #cols AS NVARCHAR(MAX) , #query AS NVARCHAR(MAX)
SELECT #cols = STUFF(( SELECT DISTINCT ',' + QUOTENAME(Vtype)
FROM dbo.VType_tbl FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #query =
'SELECT LocName,Date, ' + #cols + '
from (
select l.LocName,v.Vtype, convert(date, dtime) as Date
from Transaction_tbl t
join VType_tbl v on t.vtid = v.vtid
join dbo.Location_tbl l on t.locid=l.Locid
where dtime between ''' + #startdate + ''' and ''' + #enddate + ''' order by l.LocName
) d
pivot (
count(Vtype) for Vtype in (' + #cols + ')
) p '
EXEC sys.sp_executesql #query
End
i want to get my locname in ascending order but while giving
order by l.LocName getting error :The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries
We can fix the problem very easily by adding a TOP 100 PERCENT clause into the view definition.
Try using this way -
http://www.sqlpassion.at/archive/2015/05/25/the-ambiguity-of-the-order-by-in-sql-server/
Try migrating your order by clause into the outermost select statement — the only place where order by makes any sense.
Something like
select LocName ,
...
from ...
order by LocName
Or, even simpler, wrap the original, complex select in an outer select whose sole purpose is ordering, along these lines:
select *
from ( select
...
) t
order by t.x, t.y , ...

Resources