Field Not Generated in SRRS from Stored Procedure - reporting-services

I Exec one procedure to generate column and use in SRRS dataset :
here's my SP :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[CrossTab_MultiLV]
( #Select varchar(2000),
#Pivots1Col varchar(100),
#Summaries varchar(500),
#GroupBy varchar(100),
#OtherCols varchar(1000) = Null)
AS
set nocount on
set ansi_warnings on
declare #Vals varchar(8000);
set #Vals = '';
set #OtherCols= isNull(', ' + #OtherCols,'')
create table #temp (Pivots1 varchar(100))
insert into #temp
exec ('select distinct convert(varchar(100),' + #Pivots1Col + ',101) as Pivots1 FROM (' + #Select + ') A')
select #Vals = #Vals + ', ' +
replace(replace(#Summaries,'(','(CASE WHEN ' + #Pivots1Col + '=''' + Pivots1 + ''' THEN '),')[', ' END) as [' + Pivots1 )
from #Temp
order by Pivots1
drop table #Temp
exec ( 'select ' + #GroupBy + #OtherCols + #Vals +
' from (' + #Select + ') A GROUP BY ' + #GroupBy)
set nocount off
set ansi_warnings on
from sp above I just want to process something and generate field by those SP Produce multiple column , but only show the two first column
:
range TotalAccount CL_Only CL_Only_Have_Rate CL_Only_No_Rate EU_CL EU_CL_Have_Rate EU_CL_No_Rate EU_Only EU_Only_Have_Rate EU_Only_No_Rate
12 3 1 1 0 2 2 0 0 0 0
it'll only show : range TotalAccount column , is there any mistake in my stored procedure ??

I would abandon the dynamic stored procedure design - SSRS does not work with these.
Instead I would present the data with fixed columns and use a Column Group in the SSRS design.

Related

OPENJSON in compatibility level 100 SQL SERVER 2016

I need to use the functionality of OPENJSON() in an old database with compatibility level 100. The server runs SQL SERVER 2016. So i came up with this idea: Create another DB "GeneralUTILS" (lvl 130) in the same server and call this function from lvl 100 DB:
CREATE FUNCTION [dbo].[OPENJSON_](#json NVARCHAR(MAX))
RETURNS #Results TABLE ([Key] nVARCHAR (4000) , [Value] NVARCHAR(MAX), [Type] INT)
AS
BEGIN
INSERT INTO #Results
SELECT * from OPENJSON(#json)
RETURN
END
But i don't have the WITH clause to modify the output table in the lvl 100 database.
Most important might be the question why you need this at all...
I hope I got correctly, what you need:
(Hint: This needs at least SQL-Server 2016)
--create two mock-up-databases
CREATE DATABASE dbOld;
GO
ALTER DATABASE dbOld SET COMPATIBILITY_LEVEL = 100; --v2008
GO
CREATE DATABASE dbForJsonIssues;
GO
ALTER DATABASE dbForJsonIssues SET COMPATIBILITY_LEVEL = 130; --v2016
GO
--Now we will create a stored procedure in the "higher" database
USE dbForJsonIssues;
GO
--Attention: replacing FROM is a very hacky way... Read the hints at the end...
--You might use parameters for the JSON-string and the JSON-path, but then you must use sp_executesql
CREATE PROCEDURE EXEC_Json_Command #Statement NVARCHAR(MAX), #TargetTable NVARCHAR(MAX)
AS
BEGIN
DECLARE #statementWithTarget NVARCHAR(MAX)=REPLACE(#Statement,'FROM',CONCAT(' INTO ',#TargetTable,' FROM'));
PRINT #statementWithTarget; --you can out-comment this line...
EXEC(#statementWithTarget);
END
GO
--Now we go into the "lower" database
USE dbOld;
GO
--A synonym is not necessary, but allows for easier code
CREATE SYNONYM dbo.ExecJson FOR dbForJsonIssues.dbo.EXEC_Json_Command;
GO
--This is how to use it
DECLARE #json NVARCHAR(MAX)=N'[{"someObject":[{"attr1":"11", "attr2":"12"},{"attr1":"21", "attr2":"22"}]}]';
DECLARE #Statement NVARCHAR(MAX)=CONCAT(N'SELECT * FROM OPENJSON(N''',#json,N''',''$[0].someObject'') WITH(attr1 INT,attr2 INT)');
--the target table will be created "on the fly"
--You can use ##SomeTarget too, but be careful with concurrencies in both approaches...
EXEC ExecJson #Statement=#Statement,#TargetTable='dbOld.dbo.SomeTarget';
SELECT * FROM SomeTarget;
--We can drop this table after dealing with the result
DROP TABLE SomeTarget;
GO
--Clean-up (carefull with real-data!)
USE master;
GO
DROP DATABASE dbOld;
DROP DATABASE dbForJsonIssues;
The most important concepts:
We cannot use the JSON-statements directly within the database, but we can create a statement on string base, pass it to the stored procedure and use EXEC() for its execution.
Using SELECT * INTO SomeDb.SomeSchema.SomeTargetTable FROM ... will create a table with the fitting structure. Make sure to use a table not existing in your database.
It is not really needed to pass the target table as parameter, you might place this in the statement yourself. Replacing the FROM in the stored procedure is a very shrewed way and could lead into troubles if from is found in another place.
You might use similar procedures for various needs...
Yeah. No way this would pass the smoke screen at our office. Anyway someone asked me to do something similar, but the use case was for parsing json arrays only. Since Json_Query and Json_Value are available I hacked this together just to give them something to work with. My colleague liked the results. Turns out he's much cooler than I am after he modified it.
Declare #Fields NVarchar(2000) = 'Name,Coolness'
Declare #Delimiter As Varchar(10) = ',';
Declare #Xml As Xml = Cast(('<V>' + Replace(#Fields, #delimiter, '</V><V>') + '</V>' ) As Xml);
Declare #Json Nvarchar(4000) = N'{"Examples":[{"Name": "Chris","Coolness": "10"},{"Name": "Jay","Coolness": "1"}]}';
Exec ('Begin Try Drop Table #JsonTemp End Try Begin Catch End Catch');
Create Table #JsonTemp (JsonNode Nvarchar(1000));
Declare #Max INTEGER = 100;
Declare #Index INTEGER = 0;
While #Index < #Max
Begin
Declare #Affected Integer = 0;
Declare #Select Nvarchar(200) = '''' + 'lax$.Examples[' + Convert(Nvarchar, #Index) + ']' + '''';
Declare #Statement Nvarchar(2000)= 'Select Json_Query(' + '''' + #Json + '''' + ', ' + #Select + ') Where Json_Query(' + '''' + #Json + '''' + ', ' + #Select + ') Is Not Null';
Insert Into #JsonTemp (JsonNode) Exec sp_executesql #Statement;
Set #Affected = ##RowCount;
If (#Affected = 0) Begin Break End
Set #Index = #Index + 1;
End
Declare #Table Table(Field NVarchar(200));
Declare #Selector NVarchar(500) = 'Json_Value(' + '''' + '{"Node":' + '''' + ' + ' + 'JsonNode' + ' + ' + '''' + '}' + '''' + ', ' + '''' + '$.Node.#Field' + '''' + ')';
Insert Into #Table(Field)
Select N.value('.', 'Varchar(10)') As Field
From #XML.nodes('V') As A(N);
Declare #Selectors Varchar(8000);
Select #Selectors = Coalesce(#Selectors + ', ', '') + Replace(#Selector, '#Field', Field) + ' As ' + Field
From #Table
Exec ('Select ' + #Selectors + ' From #JsonTemp');

Convert dynamically SQL Server 2008 Table to HTML table

Is there a way I can convert a SQL Server 2008 Table to HTML table text, without knowing the structure of the table first?
I tried this:
USE [Altiris]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spCustomTable2HTML] (
#TABLENAME NVARCHAR(500),
#OUTPUT NVARCHAR(MAX) OUTPUT,
#TBL_STYLE NVARCHAR(1024) = '',
#HDR_STYLE NVARCHAR(1024) = '')
AS
-- #exec_str stores the dynamic SQL Query
-- #ParmDefinition stores the parameter definition for the dynamic SQL
DECLARE #exec_str NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(500)
--We need to use Dynamic SQL at this point so we can expand the input table name parameter
SET #exec_str= N'
DECLARE #exec_str NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(500)
--Make a copy of the original table adding an indexing columnWe need to add an index column to the table to facilitate sorting so we can maintain the
--original table order as we iterate through adding HTML tags to the table fields.
--New column called CustColHTML_ID (unlikely to be used by someone else!)
--
select CustColHTML_ID=0,* INTO #CustomTable2HTML FROM ' + #TABLENAME + '
--Now alter the table to add the auto-incrementing index. This will facilitate row finding
DECLARE #COUNTER INT
SET #COUNTER=0
UPDATE #CustomTable2HTML SET #COUNTER = CustColHTML_ID=#COUNTER+1
-- #HTMLROWS will store all the rows in HTML format
-- #ROW will store each HTML row as fields on each row are iterated through
-- using dymamic SQL and a cursor
-- #FIELDS will store the header row for the HTML Table
DECLARE #HTMLROWS NVARCHAR(MAX) DECLARE #FIELDS NVARCHAR(MAX)
SET #HTMLROWS='''' DECLARE #ROW NVARCHAR(MAX)
-- Create the first HTML row for the table (the table header). Ignore our indexing column!
SET #FIELDS=''<tr ' + #HDR_STYLE + '>''
SELECT #FIELDS=COALESCE(#FIELDS, '' '','''')+''<td>'' + name + ''</td>''
FROM tempdb.sys.Columns
WHERE object_id=object_id(''tempdb..#CustomTable2HTML'')
AND name not like ''CustColHTML_ID''
SET #FIELDS=#FIELDS + ''</tr>''
-- #ColumnName stores the column name as found by the table cursor
-- #maxrows is a count of the rows in the table, and #rownum is for marking the
-- ''current'' row whilst processing
DECLARE #ColumnName NVARCHAR(500)
DECLARE #maxrows INT
DECLARE #rownum INT
--Find row count of our temporary table
SELECT #maxrows=count(*) FROM #CustomTable2HTML
--Create a cursor which will look through all the column names specified in the temporary table
--but exclude the index column we added (CustColHTML_ID)
DECLARE col CURSOR FOR
SELECT name FROM tempdb.sys.Columns
WHERE object_id=object_id(''tempdb..#CustomTable2HTML'')
AND name not like ''CustColHTML_ID''
ORDER BY column_id ASC
--For each row, generate dymanic SQL which requests the each column name in turn by
--iterating through a cursor
SET #rowNum=0
SET #ParmDefinition=N''#ROWOUT NVARCHAR(MAX) OUTPUT,#rowNum_IN INT''
While #rowNum < #maxrows
BEGIN
SET #HTMLROWS=#HTMLROWS + ''<tr>''
SET #rowNum=#rowNum +1
OPEN col
FETCH NEXT FROM col INTO #ColumnName
WHILE ##FETCH_STATUS=0
BEGIN
--Get nth row from table
--SET #exec_str=''SELECT #ROWOUT=(select top 1 ['' + #ColumnName + ''] from (select top '' + cast(#rownum as varchar) + '' * from #CustomTable2HTML order by CustColHTML_ID ASC) xxx order by CustColHTML_ID DESC)''
SET #exec_str=''SELECT #ROWOUT=(select ['' + #ColumnName + ''] from #CustomTable2HTML where CustColHTML_ID=#rowNum_IN)''
EXEC sp_executesql
#exec_str,
#ParmDefinition,
#ROWOUT=#ROW OUTPUT,
#rowNum_IN=#rownum
SET #HTMLROWS =#HTMLROWS + ''<td>'' + #ROW + ''</td>''
FETCH NEXT FROM col INTO #ColumnName
END
CLOSE col
SET #HTMLROWS=#HTMLROWS + ''</tr>''
END
SET #OUTPUT=''''
IF #maxrows>0
SET #OUTPUT= ''<table ' + #TBL_STYLE + '>'' + #FIELDS + #HTMLROWS + ''</table>''
DEALLOCATE col
'
DECLARE #ParamDefinition nvarchar(max)
SET #ParamDefinition=N'#OUTPUT NVARCHAR(MAX) OUTPUT'
--Execute Dynamic SQL. HTML table is stored in #OUTPUT which is passed back up (as it's
--a parameter to this SP)
EXEC sp_executesql #exec_str,
#ParamDefinition,
#OUTPUT=#OUTPUT OUTPUT
RETURN 1
but when I execute the procedure
DECLARE #HTML NVARCHAR(MAX)
EXEC SpCustomTable2HTML 'Users', #HTML OUTPUT
SELECT #HTML
it keeps returning null.
Any ideas?
This SQL Fiddle DEMO shows your problem. When ALL the columns in ALL rows have values, you get a proper HTML table. When ANY NULLs exist, it turns the entire thing into NULL because
NULL + <any> = NULL
To fix it, simply change line 90 to handle nulls, i.e.
SET #HTMLROWS =#HTMLROWS + '''' + ISNULL(#ROW,'''') + ''''
The fixed SQL Fiddle DEMO
I realise it's been a while (to say the least) since this question was active but I thought I would post a few comments on this thread, as it turned up in a recent search.
Apologies if this (unintentionally) annoys the question asker but I believe the approach being used is both inefficient and difficult to understand - and therefore maintain.
There's no need to copy the database data before using it to generate the HTML table. It's just my humble opinion, but using dynamic SQL to generate dynamic SQL is also counter-intuitive.
Furthermore, database data values that contain HTML tags (or, worse still, malformed HTML tags) need to be escaped, so that they can be rendered correctly. For example, database data such as "value > 10" needs to generate the HTML "<td>value > 10</td>".
The following code addresses all of the above points, by using the built-in FOR XML clause:
CREATE PROCEDURE dbo.spCustomTable2HTML
#TABLENAME nvarchar(500),
#TBL_STYLE nvarchar(1024) = '',
#HDR_STYLE nvarchar(1024) = '',
#OUTPUT nvarchar(MAX) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
-- Declare variables
DECLARE #Columns nvarchar(MAX) = '',
#Data nvarchar(MAX),
#SQL nvarchar(MAX);
-- Snapshot columns (to force use of tempdb)
IF OBJECT_ID('tempdb.dbo.##spCustomTable2HTMLColumns') IS NOT NULL
BEGIN
DROP TABLE ##spCustomTable2HTMLColumns;
END
SET #SQL =
'SELECT TOP 0 *
INTO ##spCustomTable2HTMLColumns
FROM ' + #TABLENAME;
EXEC sp_executesql #SQL;
-- Build header row
SET #OUTPUT = (SELECT name AS td
FROM tempdb.sys.columns
WHERE object_id = OBJECT_ID('tempdb.dbo.##spCustomTable2HTMLColumns')
ORDER BY column_id
FOR XML RAW(''), ELEMENTS);
SET #OUTPUT += '</tr>'
-- Build column list
SELECT #Columns += '[' + name + '] AS td,'
FROM tempdb.sys.columns
WHERE object_id = OBJECT_ID('tempdb.dbo.##spCustomTable2HTMLColumns')
ORDER BY column_id;
SET #Columns = LEFT(#Columns, LEN(#Columns) - 1); -- Strip trailing comma
-- Delete columns snapshot
DROP TABLE ##spCustomTable2HTMLColumns;
-- Build data rows
SET #SQL =
'SET #Data = CONVERT(varchar(MAX),
(SELECT ' + #Columns +
' FROM ' + #TABLENAME +
' FOR XML RAW (''tr''), ELEMENTS XSINIL))';
EXEC sp_executesql #SQL, N'#Data NVARCHAR(MAX) OUTPUT', #Data = #Data OUTPUT;
SET #Data = REPLACE(#Data, ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"', ''); -- Remove XSI namespace
SET #Data = REPLACE(#Data, ' xsi:nil="true"', ''); -- Remove XSI attributes
SET #OUTPUT += #Data;
-- Prefix table/row headers
SET #OUTPUT = REPLACE(#OUTPUT, ' ', ' '); -- Use non-breaking spaces
SET #OUTPUT = REPLACE(#OUTPUT, '</tr>', '</tr>' + CHAR(13) + CHAR(10)); -- Add new line per row (to improve rendering in Microsoft Outlook)
SET #OUTPUT = '<table ' + #TBL_STYLE + '>' +
'<tr ' + #HDR_STYLE + '>' +
#OUTPUT +
'</table>';
END

Creating 'util' - stored procedure section, as with .net helper classes

A few minutes ago I was only searching for a simple syntax (SQL server) query that will copy a table Row .
This is usually done from time to time, when working on a ASP.net project, testing data with queries
inside the SQL SERVER management studio . so one of the routine actions is copying a row, altering the required columns to be different from each other, then testing data with queries
So I've encountered - this stored procedure- ,as answer by Dan Atkinson
but adding it to where all non testing purpose are stored lead me to think
is it possible to store them in sorted order so I could Distinguish
'utils' or 'testingPurpose' ones from those used in projects
(default folder inside managment treeview is Programmabilty) could this be another folder too
or this is not an option ?
if not , I thought of Utils. prefix like that (if no other way exist)
dbo.Utils.CopyTableRow
dbo.Utils.OtherRoutineActions ....
Or there's a designated way to achieve what I was thinking of.
this is a first "Util" stored procedure i've made , found it's only solution
prefexing it via Util_
ALTER PROCEDURE [dbo].[Utils_TableRowCopy](
#TableName VARCHAR(50) ,
#RowNumberToCopy INT
)
AS
BEGIN
declare #RowIdentity sysname =
(SELECT name FROM sys.identity_columns WHERE object_id = object_id(#TableName)
)
DECLARE #columns VARCHAR(5000), #query VARCHAR(8000);
SET #query = '' ;
SELECT #columns =
CASE
WHEN #columns IS NULL THEN column_name
ELSE #columns + ',' + column_name
END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (
TABLE_NAME = LTRIM(RTRIM(#TableName))
AND
column_name <> LTRIM(RTRIM(#RowIdentity))
);
SET #query = 'INSERT INTO ' + #TableName + ' (' + #columns + ') SELECT ' + #columns + ' FROM ' + #TableName + ' WHERE ' + #RowIdentity + ' = ' + CAST(#RowNumberToCopy AS VARCHAR);
--SELECT SCOPE_IDENTITY();
declare #query2 VARCHAR(100) = ' Select Top 1 * FROM '+ #TableName +' Order BY ' + #RowIdentity + ' desc' ;
EXEC (#query);
EXEC (#query2);
END

insert command SQL server -identity Pkey autoincrement - column name by type , in "where condition"

i would like to alter a stored procedure so i will not suplly the identity column name
INSERT INTO tablName ..... WHERE IDENTITY_Column = 10
can i tell sql server managment studio to just refer to the IDENTITY column so it will find
it by its type which is (at least in my tables a default) autoincremet PK ID type
You haven't really given enough code for us to see what you are trying to do but from the snippet in the question.
WHERE IDENTITY_Column = 10
You can just use
WHERE $IDENTITY = 10
for that (to filter against an identity column without specifying the name).
If you do actually need to lookup the column name then an easier way, avoiding deprecated views is
SELECT name
FROM sys.identity_columns
WHERE object_id = object_id('dbo.YourTable')
found this information by now .
that is the plain and simple version .
declare #tblName sysname = '______'--<== enter a table name
declare #NameOfIDColumn sysname =
(
SELECT Name
FROM syscolumns
WHERE COLUMNPROPERTY( id ,name, 'IsIdentity') = 1 and OBJECT_NAME(id)= #tblName )
select #NameOfIDColumn AS 'result'
you could add this as an option to display last row of a table soretd by its record#
declare #query VARCHAR(100) = 'Select Top 1 * FROM '+ #tblName +' Order BY ' + #IdentColumnName + ' desc' ;
EXEC (#query);
and to play around or even make it as a test page in a .net project
make this one as a stored proc that will outpout a message to a test page .
declare #tblName sysname = '______'--<== enter a table name
declare #IdentColumnName sysname =
(
SELECT Name
FROM syscolumns
WHERE COLUMNPROPERTY( id ,name, 'IsIdentity') = 1 and OBJECT_NAME(id)= #tblName )
declare #result VARCHAR (50) = #tblName + ' Identity Column is ' + #IdentColumnName;
select #result AS 'result'
and with a shorter version of "idntity column search", by Martin Smith
declare #tblName sysname = '______'--<== enter a table name
declare #IdentColumnName sysname =
(SELECT name FROM sys.identity_columns WHERE object_id = object_id(#TableName))
declare #result VARCHAR (50) = #tblName + ' Identity Column is ' + #IdentColumnName;
select #result AS 'result'
this is related to a table copy trick i was trying to pull via stored procedure.
USE [YourDataBaseName]
GO
/****** Object: StoredProcedure [dbo].[Utils_TableRowCopy] Script Date: 10/03/2012 18:26:58 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Utils_TableRowCopy](
#TableName VARCHAR(50) ,
#RowNumberToCopy INT
)
AS
BEGIN
declare #RowIdentity sysname =
(
SELECT name FROM sys.identity_columns WHERE object_id = object_id(#TableName)
)
DECLARE #columns VARCHAR(5000), #query VARCHAR(8000);
SET #query = '' ;
SELECT #columns =
CASE
WHEN #columns IS NULL THEN column_name
ELSE #columns + ',' + column_name
END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (
TABLE_NAME = LTRIM(RTRIM(#TableName))
AND
column_name <> LTRIM(RTRIM(#RowIdentity))
);
SET #query = 'INSERT INTO ' + #TableName + ' (' + #columns + ') SELECT ' + #columns + ' FROM ' + #TableName + ' WHERE ' + #RowIdentity + ' = ' + CAST(#RowNumberToCopy AS VARCHAR);
--SELECT SCOPE_IDENTITY();
declare #query2 VARCHAR(100) = ' Select Top 1 * FROM '+ #TableName +' Order BY ' + #RowIdentity + ' desc' ;
EXEC (#query);
EXEC (#query2);
END

Dynamic sql insert into returns 'invalid column name'

I'm trying my first dynamic sql stored procedure. I need to append the exact same records into multiple tables with the same column names. What I have compiles, but when it runs I get 'invalid column name 'TradeDate. The driver sproc is first below, then the sproc containing the dynamic statement. If anyone could help, that'd be great..
ALTER PROCEDURE dbo.StoredProcedure2
AS
DECLARE #tableName varchar(120)
SET #tableName = 'tblDailyATR'
EXEC sprocAddDatesAndSymbolsToAggregatedStudy #tableName
RETURN
ALTER PROCEDURE dbo.sprocAddDatesAndSymbolsToAggregatedStudy
#table varchar(120)
AS
DECLARE #tableName varchar(120)
SET #tableName = #table
EXEC(
'INSERT INTO ' + #tableName + '(Symbol, TradeDate)
SELECT Symbol, TradingDate
FROM (SELECT tblSymbolsMain.Symbol, tblTradingDays.TradingDate
FROM tblSymbolsMain CROSS JOIN tblTradingDays
WHERE (tblTradingDays.TradingDate <= dbo.NextAvailableDataDownloadDate())) AS T1
WHERE (NOT EXISTS (SELECT TradeDate, Symbol
FROM' + #tableName +
' WHERE (TradeDate = T1.TradingDate) AND (Symbol = T1.Symbol)))')
RETURN
You're missing a space after the "FROM" in this line:
FROM' + #tableName +
Should be
FROM ' + #tableName +
Otherwise it's going to try running SELECT FROMTABLE.