How to execute string as query inside a CTE in SQL Server - sql

I am using CTE like below... But I am getting an error like
No column name was specified for column 1 of 'TempResult'.
Also here I am passing #Query from another stored procedure, and in this procedure I need to execute that #Query inside CTE TempResult.
CREATE PROCEDURE [dbo].[SelectAllProjectPaging]
#CurrentPage int,
#RecordsPerPage int,
#Column varchar(50),
#Query nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #query nvarchar(max)
SET #query = 'ROW_NUMBER() OVER(ORDER BY ProjectList.ProjectId DESC) as RowNumber,' + #Query
-- Insert statements for procedure here
DECLARE #FirstRecord int, #LastRecord int
SELECT #FirstRecord = (#CurrentPage - 1) * #RecordsPerPage
SELECT #LastRecord = (#CurrentPage * #RecordsPerPage + 1);
WITH TempResult as
(
Select #query
)
SELECT TOP (#LastRecord - 1) *
FROM TempResult
WHERE RowNumber > #FirstRecord
AND RowNumber < #LastRecord;
SELECT COUNT(*) as count
FROM ProjectList
End

You need to make the entire query with dynamic sql. something like this:
SET #query= 'WITH TempResult as
(
SELECT + ' + #query +
')
SELECT TOP (' + CAST((#LastRecord - 1) AS VARCHAR(20)) +
') * FROM TempResult
WHERE RowNumber > ' + CAST(#FirstRecord AS VARCHAR(20)) +
' AND RowNumber < ' + CAST(#LastRecord AS VARCHAR(20)) + '; '
EXECUTE #query
Edit
To the comment. Yes it should select what I can see. The #query is equals to:
set #query = 'ROW_NUMBER() OVER(ORDER BY ProjectList.ProjectId DESC) as RowNumber,'+ #query
Then you will need:
SELECT ' ROW_NUMBER() OVER(ORDER BY ProjectList.ProjectId DESC) as RowNumber,' + #query

Your "With TempResult As" has to be extended a bit, containing the column names to be used.
Example
With TempResult (column1, column2, column3) as
(
select #query
)
Ref:
WITH expression_name [ ( column_name [,...n] ) ]
AS
( CTE_query_definition )
From http://technet.microsoft.com/en-us/library/ms190766%28v=sql.105%29.aspx

Related

How do I use loop to generate column names dynamically?

I have table sdata and it has 35 columns (id, name, TRx1, TRx2, TRx3, TRx4,..., TRx30, city, score, total)
I want to fetch data from the TRx1,...TRx30 columns.
Can I use loop here?
I did following code:
DECLARE #flag INT
DECLARE #sel varchar(255)
DECLARE #frm varchar(255)
SET #flag = 1;
SET #sel = 'select TRx';
SET #frm = ' from sdata';
exec(#sel +
(WHILE #flag <=5
#flag
SET #flag = #flag + 1)
+ #frm)
What wrong am I doing? And how can I resolve this?
If your table name is sdata, this code should work for you:
-- Grab the names of all the remaining columns
DECLARE #sql nvarchar(MAX);
DECLARE #columns nvarchar(MAX);
SELECT #columns = STUFF ( ( SELECT N'], [' + name
FROM sys.columns
WHERE object_id = (select top 1 object_id FROM sys.objects where name = 'sdata')
AND name LIKE 'TRx%' -- To limit which columns
ORDER BY column_id
FOR XML PATH('')), 1, 2, '') + ']';
PRINT #columns
SELECT #sql = 'SELECT ' + #columns + ' FROM sdata';
PRINT #sql;
EXEC (#sql);
Note I included PRINT statements so you could see what's going on. You might want to comment out the EXEC while testing.
This would be much easier to do by just copy/pasting the column names and changing them to be the correct one. However if you must do it this way, I do not advise using a loop at all. This method uses a tally table to generate the columns you want to select (in this example, columns 1 through 30, but that can be changed), then generates a dynamic SQL statement to execute against the SData table:
Declare #From Int = 1,
#To Int = 30,
#Sql NVarchar (Max)
Declare #Columns Table (Col Varchar (255))
;With Nums As
(
Select *
From (Values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) As V(N)
), Tally As
(
Select Row_Number() Over (Order By (Select Null)) As N
From Nums A --10
Cross Join Nums B --100
Cross Join Nums C --1000
)
Insert #Columns
Select 'TRx' + Cast(N As Varchar)
From Tally
Where N Between #From And #To
;With Cols As
(
Select (
Select QuoteName(Col) + ',' As [text()]
From #Columns
For Xml Path ('')
) As Cols
)
Select #Sql = 'Select ' + Left(Cols, Len(Cols) - 1) + ' From SData'
From Cols
--Select #Sql
Execute (#Sql)
Note: The --Select #Sql section is there to preview the generated query before executing it.
You can select the column names like this:
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'my name here'

Defining dynamic PIVOT sql query in SQL Server

Currently I have a static pivot sql query defined in a stored procedure in sql server:
ALTER PROCEDURE [dbo].[MonthRepo]
-- Add the parameters for the stored procedure here
#from datetime,
#to datetime
AS
BEGIN
DECLARE #cols nvarchar(12)
DECLARE #query nvarchar(max)
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT *
FROM (
SELECT ROUND(ds.ct_quot_rate,0) AS Quote,
ROUND(ds.ct_quot_rate,0) AS Quote_Out,
ds.isin
FROM ds
WHERE ds.datum >= #from AND ds.datum <= #to
) tbl
PIVOT (
COUNT(Quote)
FOR isin IN(AB000001,
AB000002,
AB000003,
AB000004,
AB000005)
) piv
END
How can I define this static code in dynamic query? I have declared 2 variables.
I think you're after something like this:
ALTER PROCEDURE [dbo].[MonthRepo]
-- Add the parameters for the stored procedure here
#from datetime,
#to datetime
AS
BEGIN
DECLARE #cols nvarchar(max)
DECLARE #query nvarchar(max)
SET NOCOUNT ON;
WITH vals AS (
SELECT DISTINCT isin
FROM ds
)
SELECT #cols = COALESCE(#cols + ',','') + '[' + isin + ']'
FROM vals
SET #query = '
SELECT *
FROM (
SELECT ROUND(ds.ct_quot_rate,0) AS Quote,
ROUND(ds.ct_quot_rate,0) AS Quote_Out,
ds.isin
FROM ds
WHERE ds.datum >= #from_param AND ds.datum <= #to_param
) tbl
PIVOT (
COUNT(Quote)
FOR isin IN(' + #cols + ' )
) piv'
EXECUTE sp_executesql #query, N'#from_param DATETIME, #to_param DATETIME', #from_param = #from, #to_param = #to
END
CREATE PROCEDURE [dbo].[MonthRepo]
-- Add the parameters for the stored procedure here
#from VARCHAR(20),
#to VARCHAR(20)
AS
BEGIN
IF OBJECT_ID('tempdb..#T') IS NOT NULL
DROP TABLE #T
create table #T
(
datnum varchar(20),
quote INT,
isin VARCHAR(20)
)
insert into #T (datnum,quote,isin)values ('2015-01-01',100,'AB000001'),
('2015-01-01',100,'AB000002'),
('2015-01-02',98,'AB000003'),
('2015-01-02',70,'AB000001'),
('2015-01-03',100,'AB000001')
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = Isnull(#columns + ', ', '') + N'[' + tbl.isin+ ']'
FROM (SELECT DISTINCT isin
FROM #T) AS tbl
--SELECT #columns
SELECT #statement = ' SELECT *
FROM (
SELECT ROUND(ds.quote,0) AS Quote,
ROUND(ds.quote,0) AS Quote_Out,
ds.isin
FROM #T ds
WHERE ds.datnum >= CONVERT(datetime,'+''''+#from+''' ,105) AND ds.datnum <= CONVERT(datetime,'''+#to+''' ,105)
) tbl
PIVOT (
COUNT(Quote)
FOR isin IN(' + #columns+ ')) as PVT
'
PRINT #statement
EXEC sp_executesql #statement = #statement
END
EXEC [MonthRepo] #from = '2015-01-01',#to = '2015-01-10'

Get top three most common values from every column in a table

I'm trying to write a query that will produce a very small sample of data from each column of a table, in which the sample is made up of the top 3 most common values. This particular problem is part of a bigger task, which is to write scripts that can characterize a database and its tables, its data integrity, and also quickly survey common values in the table on a per-column basis. Think of this as an automated "analysis" of a table.
On a single column basis, I do this already by simply calculating the frequency of values and then sorting by frequency. If I had a column called "color" and all colors were in it, and it just so happened that the color "blue" was in most rows, then the top 1 most frequently occurring value would be "blue". In SQL that is easy to calculate.
However, I'm not sure how I would do this over multiple columns.
Currently, when I do a calculation over all columns of a table, I perform the following type of query:
USE database;
DECLARE #t nvarchar(max)
SET #t = N'SELECT '
SELECT #t = #t + 'count(DISTINCT CAST(' + c.name + ' as varchar(max))) "' + c.name + '",'
FROM sys.columns c
WHERE c.object_id = object_id('table');
SET #t = SUBSTRING(#t, 1, LEN(#t) - 1) + ' FROM table;'
EXEC sp_executesql #t
However, its not entirely clear to me how I would do that here.
(Sidenote:columns that are of type text, ntext, and image, since those would cause errors while counting distinct values, but i'm less concerned about solving that)
But the problem of getting top three most frequent values per column has got me absolutely stumped.
Ideally, I'd like to end up with something like this:
Col1 Col2 Col3 Col4 Col5
---------------------------------------------------------------------
1,2,3 red,blue,green 29,17,0 c,d,j nevada,california,utah
I hacked this together, but it seems to work:
I cant help but think I should be using RANK().
USE <DB>;
DECLARE #query nvarchar(max)
DECLARE #column nvarchar(max)
DECLARE #table nvarchar(max)
DECLARE #i INT = 1
DECLARE #maxi INT = 10
DECLARE #target NVARCHAR(MAX) = <table>
declare #stage TABLE (i int IDENTITY(1,1), col nvarchar(max), tbl nvarchar(max))
declare #results table (ColumnName nvarchar(max), ColumnValue nvarchar(max), ColumnCount int, TableName NVARCHAR(MAX))
insert into #stage
select c.name, o.name
from sys.columns c
join sys.objects o on o.object_id=c.object_id and o.type = 'u'
and c.system_type_id IN (select system_type_id from sys.types where [name] not in ('text','ntext','image'))
and o.name like #target
SET #maxi = (select max(i) from #stage)
while #i <= #maxi
BEGIN
set #column = (select col from #stage where i = #i)
set #table = (select tbl from #stage where i = #i)
SET #query = N'SELECT ' +''''+#column+''''+' , '+ #column
SELECT #query = #query + ', COUNT( ' + #column + ' ) as count' + #column + ' , ''' + #table + ''' as tablename'
select #query = #query + ' from ' + #table + ' group by ' + #column
--Select #query
insert into #results
EXEC sp_executesql #query
SET #i = #i + 1
END
select * from #results
; with cte as (
select *, ROW_NUMBER() over (partition by Columnname order by ColumnCount desc) as rn from #results
)
select * from cte where rn <=3
Start with this SQL Statement builder, and modify it to suit your liking:
EDIT Added Order by Desc
With ColumnSet As
(
Select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
From INFORMATION_SCHEMA.COLUMNS
Where 1=1
And TABLE_NAME IN ('Table1')
And COLUMN_NAME IN ('Column1', 'Column2')
)
Select 'Select Top 3 ' + COLUMN_NAME + ', Count (*) NumInstances From ' + TABLE_SCHEMA + '.'+ TABLE_NAME + ' Group By ' + COLUMN_NAME + ' Order by Count (*) Desc'
From ColumnSet

Fill dynamic array with values from an array

I have to execute a similar query on many tables. Instead of writing an n amount of almost similar similar queries, I would like to use a dynamic query. Pseudo:
array = (
'table_a' => 'value_a',
'table_b' => 'value_b',
'table_c' => 'value_c'
);
foreach (array as table => value)
exec(
'select ' + #value + ' into #' + #table + ' from ' + #table
);
end
Is something like this possible in SQL Server 2008 RE? Any help would be greatly appreciated!
You can do this in SQL Server using something like the following script:
CREATE TABLE #temp (id INT IDENTITY(1,1), tablename VARCHAR(50))
INSERT INTO #temp
( tablename )
VALUES ( 'table_a' ),('table_b'),('table_c')
DECLARE #sql NVARCHAR(MAX)
DECLARE #tblcount INT, #i INT = 1
SELECT #tblcount = MAX(id) FROM #temp
WHILE #i <= #tblcount
BEGIN
SELECT #sql = 'SELECT t.somefield, t.otherfield as ' + tablename + ' INTO #some_temptable_' + tablename + ' FROM #mytable t where SomeField like ''1''' FROM #temp WHERE id = #i
EXEC sp_executesql #sql
--SELECT #sql
SELECT #i = #i + 1
END
DROP TABLE #temp

SQL Exec can't execute long strings

This is my code
DECLARE #sql nvarchar(4000)
set #sql = 'WITH CTE AS
(
Select *, ROW_NUMBER() OVER (ORDER BY ' + #order + ' ' + #Desc + ') AS RowNum
from (SELECT ID, Subject from a
WHERE (Subject LIKE N''%'' + #searchText + N''%''))
)
SELECT *
FROM CTE
WHERE RowNum BETWEEN (#pageIndex - 1) * #pageSize + 1
AND #pageIndex * #pageSize ;';
where #order = "ID" and #pageIndex = 1 and #pageSize = 5 and #searchText = 'a' and #Desc = 'DESC'
I wrote
select #sql
to see if #sql is executable. I copied it and pasted it and ran it. it worked.
then I wrote
exec #sql
error! it seems exec just tried to execute some characters from the first of #sql. Is there any limitations on #sql?
p.s: The error is like this
The name '.........someth' is not a valid identifier.
Please try the below code.
DECLARE #sql nvarchar(max)
set #sql = '.............something executable.................';
This error may occurred due to length of the string exceed more than 4000 characters