I have a table contains the following data:
ID | expression
----|------------
1 | select 1+9
2 | select 6+23+3
----|------------
I need a query to get the result:
ID | expressionValue
----|------------
1 | 10
2 | 32
----|------------
You can try like this:
declare #x nvarchar(100)
select #x = expression from myTable where id = 1
EXECUTE sp_executesql #x
And if you want this to be done for all the rows of your table then try to create a cursor and execute it for your column like this:
DECLARE #myRes TABLE
(
ID INT ,
expression NVARCHAR(100)
)
DECLARE #temp TABLE ( ID INT )
DECLARE #ID INT ,
#expression NVARCHAR(100)
DECLARE cur CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT ID , expression FROM myTable
OPEN cur
FETCH NEXT FROM cur INTO #ID, #expression
WHILE ##FETCH_STATUS = 0
BEGIN
DELETE FROM #temp
INSERT INTO #temp
EXEC ( #expression )
INSERT INTO #myRes
VALUES ( #ID, ( SELECT * FROM #temp ) )
FETCH NEXT FROM cur INTO #ID, #expression
END
CLOSE cur
DEALLOCATE cur
SELECT * FROM #myRes
Output:
If you got only + and - in formulas - then you can use XML.query:
SELECT ID,
CAST(
REPLACE(
REPLACE(
REPLACE(expression,'select ','<v><d>')
,'+','</d><d>')
,'-','</d><d>-') + '</d></v>'
as xml).query('for $s in /v return data(fn:sum($s/d))') as expressionValue
FROM YourTable
Output:
ID expressionValue
1 10
2 32
Also you can avoid using dynamic SQL to execute SELECT formula statements and use more secure way with XML.query:
CREATE TABLE #Results ( --Table to store results
ID int,
expressionValue nvarchar(max)
)
DECLARE #sql nvarchar(max) --will hold the dynamic SQL query
SELECT #sql = COALESCE(#sql,'DECLARE #x xml = ''''; INSERT INTO #Results ') +
'SELECT '+CAST(ID as nvarchar(max))+' as ID,
CAST(#x.query('''+REPLACE(expression,'select ','')+''') as nvarchar(max)) UNION '
FROM #YourTable --query generation
SELECT #sql = LEFT(#sql,LEN(#sql)-LEN(' UNION '))
If you make PRINT #sql you will get something like:
DECLARE #x xml = '';
INSERT INTO #Results
SELECT 1 as ID,
CAST(#x.query('1+9') as nvarchar(max))
UNION
SELECT 2 as ID,
CAST(#x.query('6+23+3') as nvarchar(max))
Then execute:
EXEC sp_executesql #sql
Then you can select from #Results table:
SELECT *
FROM #Results
Output:
ID expressionValue
1 10
2 32
Try this...
create table expr(id int,epres varchar(max))
insert into expr values(1,'select 2+2')
insert into expr values(2,'select 2-1')
declare #sql varchar(max),#id int
select top 1 #sql = epres,#id=id from expr where epres is not null order by id
while ##rowcount > 0
begin
exec(#sql)
select top 1 #sql = epres ,#id=id from expr where id > #id order by id;
end;
Related
I have a sp in which I am returning one single column result. I am trying to store the result into a table type, but I am getting this error:
An INSERT EXEC statement cannot be nested.
I have googled around but didn't find any acceptable solution.
The sp is as follows:-
ALTER PROCEDURE [dbo].[Sp_DemographicFilter_booster]
(
#FilterSelected FilterSelected READONLY,
#CountryCategoryId int=null
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #WhereCondition varchar(500) ;
DECLARE #QueryString Varchar(MAX) ;
DECLARE #QueryString_booster Varchar(MAX) ;
DECLARE #Filter table (FilterColumn Varchar(200),FilterValue Varchar(200))
DECLARE #Result table (SERIAL int)
DECLARE #Result_booster table (SERIAL int)
if( select top 1 FilterColumn FROM #FilterSelected where FilterColumn<>'HISPANIC') is NOT NULL
BEGIN
Insert into #Filter
Select * from #FilterSelected where FilterColumn<>'HISPANIC'
--DECLARE #DemoTbl TABLE (MetricName VARCHAR(100),CatValue VARCHAR(100))
SELECT #WhereCondition= COALESCE( #WhereCondition + ' and ', '')+SubjectList FROM (
SELECT DISTINCT STD.Filtercolumn +' in ('+
ISNULL(STUFF((SELECT ', '+'''' + ssm.Filtervalue+''''
FROM #Filter SSM
INNER JOIN #Filter SUB ON SUB.FilterColumn = SSM.FilterColumn and SUB.FilterColumn=STD.FilterColumn
WHERE sub.FilterValue = ssm.FilterValue
FOR XML PATH('')
), 1, 1, ''), 'Not Assigned Yet')+')' AS SubjectList
FROM #Filter STD)A
print #WhereCondition
--INSERT INTO #DemoTbl
--select SUBSTRING(col1,1, CHARINDEX(':',col1,1)-1) MetricName,SUBSTRING(col1, CHARINDEX(':',col1,1)+1,LEN(Col1)) CatValue
--from dbo.UF_CSVDataToTable(#FilterSelectedSelected)
SET #QueryString='SELECT SERIAL FROM Logical.Demographic D
WHERE '+#WhereCondition+' and CountryCategoryId='+cast(#CountryCategoryId as varchar(10))
PRINT #QueryString
insert into #Result
EXEC(#QueryString)
--select * from #Result
END
IF(select top 1 FilterColumn FROM #FilterSelected where FilterColumn='HISPANIC') IS NOT NULL
BEGIN
Delete from #Filter;
DECLARE #Response varchar(20)=null;
Insert into #Filter
Select * from #FilterSelected where FilterColumn='HISPANIC'
select #Response=FilterValue from #Filter;
DECLARE #VariableID int=null;
select #VariableID=SurrogateKeyCounter from MetaData.Metadata_Screener where DBMetricName='HISPANIC';
SET #QueryString_booster='SELECT SERIAL FROM Logical.Response R
WHERE variableid='+cast(#VariableID as varchar(10))+' and CountryCategoryId='+cast(#CountryCategoryId as varchar(10))
+' and ResponseName='''+#Response+''''
PRINT #QueryString_booster
Insert into #Result_booster
EXEC(#QueryString_booster)
END
DECLARE #Final_Result table (SERIAL int)
insert into #Final_Result
select * from #Result
UNION
select * From #Result_booster
select * from #Final_Result
END
I am calling this procedure like this:
declare #ds FilterSelected
insert into #ds values('Hispanic','yes')
#FilterSelected=#ds,#CountryCategoryId=100
DECLARE #DemoTbl TABLE (Serial INT)
Insert into #DemoTbl
EXEC Sp_DemographicFilter_booster #FilterSelected=#ds,
#CountryCategoryId=100
Call SP Sp_DemographicFilter_booster along with unique ID .
Inside Sp_DemographicFilter_booster SP create global table (##) stored result in global table with same unique ID AS ID field
Now when return to main SP access global table with where condition that unique ID
I have few tables in my database and I want to count total rows of all those tables based on AppoitmentID for which I use a scalar cursor and a table variable to store some data of those tables based on AppoitmentID. After the end of cursor I count rows of table variable in which I had inserted data using dynamic query in cursor.
But it gives me the following error
Must declare the table variable "#ProcCount".
Is there any other way to get the count of all rows from necessary tables.
Below is my Code :
Create FUNCTION [dbo].[ufn_GetProcedureCount]
(
)
RETURNS INT
AS
BEGIN
-- Declare the return variable here
DECLARE #MenuID bigINT, #TableName VARCHAR(150);
DECLARE #Result int
DECLARE #ProcCount TABLE (AppID INT, WoundId bigINT,TableName varchar(150));
DECLARE #sql nvarchar(2000)
DECLARE #Count int
DECLARE Cur_PendSign Cursor For
select Distinct MenuID,TableName from AppointmentTypeRequiredDocumnet A inner join Menu M on M.ID =A.MenuID where m.MenuGroupID = 8
OPEN Cur_PendSign
FETCH Cur_PendSign INTO #MenuID, #TableName
WHILE ##FETCH_STATUS=0
BEGIN
SET #sql='DECLARE #ProcCount TABLE (AppID INT, WoundId bigINT,TableName varchar(150))'
SET #sql=#sql+'INSERT INTO #ProcCount (AppID,WoundId)
SELECT TOP 1 V.AppointmentID, 1
FROM ['+#TableName+'] V WITH(NOLOCK)'
set #sql=#sql+ 'select count(*) from #ProcCount;'
--set #sql=#sql+ 'DECLARE #Count int'
EXECUTE sp_executesql #sql
FETCH Cur_PendSign INTO #MenuID, #TableName
END
CLOSE Cur_PendSign
DEALLOCATE Cur_PendSign
--set #Result = select count(*) from #ProcCount
RETURN #Result
END
There are two issues with the script.
First: Missing where clause
select Distinct MenuID,TableName from Appointment A.AppointmentID = 8
Second: you need to create persistent table rather than variable table due to limitation of scope as you cant declare variable table outside of EXEC and use it.
This query should work for you. You need to use sp_executesql to execute dynamic queries.
CREATE FUNCTION [dbo].[ufn_GetProcedureCount]
(
)
RETURNS INT
AS
BEGIN
-- Declare the return variable here
DECLARE #Result INT
DECLARE #ProcCount TABLE (
AppID INT,
WoundId BIGINT,
TableName VARCHAR(150)
)
DECLARE #MenuID BIGINT,
#TableName VARCHAR(150)
--Get all table which I need to count rows
DECLARE Cur_PendSign CURSOR FOR
SELECT DISTINCT MenuID, TableName FROM Appointment WHERE AppointmentID = 8
OPEN Cur_PendSign
FETCH Cur_PendSign INTO #MenuID, #TableName
WHILE ##fetch_status = 0
BEGIN
-- Insert require data into #ProcCount using dynamic query
DECLARE #query VARCHAR(255) = 'INSERT INTO #ProcCount (AppID,WoundId,TableName)
SELECT TOP 1 AppointmentID, WoundId, TableName
FROM [' + #TableName + '] WITH(NOLOCK) '
EXECUTE sys.sp_executesql #query
FETCH Cur_PendSign INTO #MenuID, #TableName
END
CLOSE Cur_PendSign
DEALLOCATE Cur_PendSign
--Get Count of all rows from tables
SELECT #Result = COUNT(*) FROM #ProcCount
RETURN #Result
END
Without having a cursor, Loops you can do it with Dynamic coding..
Schema:
(It may be differ with your actual schema)
CREATE TABLE #Appointment (MENUID INT IDENTITY,AppointmentID INT, TableName VARCHAR(20))
INSERT INTO #Appointment
SELECT 1,'TABLE1'
UNION ALL
SELECT 2, 'TABLE2'
UNION ALL
SELECT 8,'TABLE3'
UNION ALL
SELECT 8,'TABLE4'
UNION ALL
SELECT 8,'TABLE5'
Now do like below
DECLARE #QRY VARCHAR(MAX)='';
SELECT #QRY = #QRY+ 'SELECT COUNT(1) AS COUNT_TABLES FROM '+ TableName + ' (NOLOCK)
UNION ALL
' FROM (
SELECT DISTINCT TableName FROM #Appointment A WHERE A.AppointmentID = 8
)A
SELECT #QRY = SUBSTRING(#QRY,1,LEN(#QRY)-11)
SELECT #QRY = '
SELECT SUM(COUNT_TABLES) FROM (
' + #QRY+'
)A'
--PRINT #QRY
EXEC (#QRY)
If you want to check what #QRY contains
/*
SELECT SUM(COUNT_TABLES) FROM (
SELECT COUNT(1) AS COUNT_TABLES FROM TABLE3 (NOLOCK)
UNION ALL
SELECT COUNT(1) AS COUNT_TABLES FROM TABLE4 (NOLOCK)
UNION ALL
SELECT COUNT(1) AS COUNT_TABLES FROM TABLE5 (NOLOCK)
)A
*/
While Executing the Following query it showing the Invalid object name '#temp1'. can any body knows the error occurred due to which reason this is my orginal code i used to fetch code , her differnt tables are formed i need to get the sum of the each row of each table
DECLARE #t TABLE (
id int IDENTITY(1,1),
BranchName nvarchar(max)
)
DECLARE #n int = 0,
#i int = 1,
#BranchName nvarchar(max),
#sql nvarchar(max),
#columns nvarchar(max)
INSERT INTO #t
SELECT DISTINCT BranchName
FROM ALX_Branches
SELECT #n = ##ROWCOUNT
WHILE #n >= #i
BEGIN
SELECT #BranchName = BranchName
FROM #t
WHERE id = #i
SELECT #columns = (
SELECT DISTINCT ','+QUOTENAME([SubInventory])
FROM #MyTempTable
WHERE [BranchName] = #BranchName
FOR XML PATH('')
)
SELECT #sql = N'--
SELECT * into #temp1
FROM (
SELECT [BranchID],
[SubInventory],
[Product],
[Stock]
FROM #MyTempTable
WHERE [BranchName] = ''' +#BranchName +'''
) as t
PIVOT (
MAX([Stock]) FOR [SubInventory] IN ('+STUFF(#columns,1,1,'')+')
) as pvt'
EXEC sp_executesql #sql
select * from #temp1
Firstly, there is no need for creating #temp1 table before.
because you are using "Select * into" that already create table within it.
Suppose type this note as a comment, but I don't have enough reputation score.
The reason of
Invalid object name '#temp1'
is: the variable #sql is NULL because #temp1 is not created yet via "Select * into" clause.
so append selecting from #temp1 within dynamic sql as the following:
SELECT #sql = N'--
SELECT * into #temp1
FROM (
SELECT [BranchID],
[SubInventory],
[Product],
[Stock]
FROM #MyTempTable
WHERE [BranchName] = ''' +#BranchName +'''
) as t
PIVOT (
MAX([Stock]) FOR [SubInventory] IN ('+STUFF(#columns,1,1,'')+')
) as pvt
select * from #temp1 '
EXEC sp_executesql #sql
I am using SQL Server 2012.
The first part of my query is already answered in this thread. But I also want a second column that will show the corresponding maximum value of that column in its corresponding table.
I have tried this approach: use a function that takes in table name and column name as parameter and return the max value. But it is illegal to use dynamic SQL from a function. Moreover, i cannot seem to call a function from within a SELECT query.
I have also tried using stored procedure, but i cannot figure out how to call it and use it. Please suggest alternative ways to achieve this.
I am new to SQL Server.
Thanks
I think the easiest solution would be stored procedure. As far as I know:
Dynamic SQL can't be placed in functions
Dynamic SQL can't be place in OPENROWSET
I addition, if you write such procedure:
Beware of names containing spaces, qoutes (SQL injection possible)
MAX(column) on non-Indexed columns would require full scan (can be very slow)
Table and column names can be duplicated (placed in differend schemas)
Id duplicates and performance is not a problem, take a look at the following snippet:
CREATE PROC FindMaxColumnValues
#type sysname = '%',
#table sysname = '%'
AS
DECLARE #result TABLE (TableName sysname, ColumnName sysname, MaxValue NVARCHAR(MAX))
DECLARE #tab sysname
DECLARE #col sysname
DECLARE cur CURSOR FOR
SELECT TABLE_NAME TableName, COLUMN_NAME [Column Name]
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE LIKE #type and TABLE_NAME LIKE #table
OPEN cur
FETCH NEXT FROM cur INTO #tab, #col
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql nvarchar(MAX) = 'SELECT '+QUOTENAME(#tab,'''')+' [TableName], '+QUOTENAME(#col, '''')+' [ColumnName], MAX('+QUOTENAME(#col)+') FROM '+QUOTENAME(#tab)
INSERT INTO #result EXEC(#sql)
FETCH NEXT FROM cur INTO #tab, #col
END
CLOSE cur
DEALLOCATE cur
SELECT * FROM #result
Samples:
--MAX of INT's
EXEC FindMaxColumnValues 'INT'
--MAX of INT's in tables matching 'TestTab%'
EXEC FindMaxColumnValues 'INT', 'TestTab%'
--MAX of ALL columns
EXEC FindMaxColumnValues
Results:
TableName ColumnName MaxValue
IdNameTest ID 2
TestTable ID 5
TestTable Number 3
TableName ColumnName MaxValue
TestTable ID 5
TestTable Number 3
TableName ColumnName MaxValue
UpdateHistory UpdateTime 2016-07-14 12:21:37.00
IdNameTest ID 2
IdNameTest Name T2
TestTable ID 5
TestTable Name F
TestTable Number 3
You can use the below SP and enhance it per your Need,
CRETE PROCEDURE Getmaxtablecolval
AS
BEGIN
CREATE TABLE #t
(
tablename VARCHAR(50),
columnname VARCHAR(50),
id INT,
counts INT
)
INSERT INTO #t
SELECT table_name [Table Name],
column_name [Column Name],
NULL,
NULL
FROM information_schema.columns
WHERE data_type = 'INT'
BEGIN TRAN
DECLARE #id INT
SET #id = 0
UPDATE #t
SET #id = id = #id + 1
COMMIT TRAN
DECLARE #RowCount INT
SET #RowCount = (SELECT Count(0)
FROM #t)
DECLARE #I INT
SET #I = 1
DECLARE #Counter INT
DECLARE #TName VARCHAR(50)
DECLARE #CName VARCHAR(50)
DECLARE #DynamicSQL AS VARCHAR(500)
WHILE ( #I <= #RowCount )
BEGIN
SELECT #TName = tablename
FROM #t
WHERE id = #I
SELECT #CName = columnname
FROM #t
WHERE id = #I
SET #DynamicSQL = 'Update #T Set Counts = '
+ '(Select ISNull(Max(' + #CName + '), 0) From '
+ #TName + ') Where Id = '
+ CONVERT(VARCHAR(10), #I)
--PRINT #DynamicSQL
EXEC (#DynamicSQL)
SET #I = #I + 1
END
SELECT *
FROM #t
END
go
Getmaxtablecolval
You can create a procedure out of this:
CREATE PROCEDURE GET_COLUMNS_WITH_MAX_VALUE
#COLUMN_TYPE NVARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- DUMMY VARIABLE TO COPY STRUCTURE TO TEMP
DECLARE #DUMMY TABLE
(
TABLE_NAME NVARCHAR(50),
COLUMN_NAME NVARCHAR(50),
MAX_VALUE NVARCHAR(MAX)
)
-- CREATE TEMP TABLE FOR DYNAMIC SQL
SELECT TOP 0 * INTO #TABLE FROM #DUMMY
INSERT INTO #TABLE
(TABLE_NAME, COLUMN_NAME)
SELECT TABLE_NAME, COLUMN_NAME
FROM information_schema.columns where data_type = #COLUMN_TYPE
DECLARE #TABLE_NAME VARCHAR(50) -- database name
DECLARE #COLUMN_NAME VARCHAR(256) -- path for backup files
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM #TABLE
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TABLE_NAME, #COLUMN_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(MAX) = 'UPDATE #TABLE SET MAX_VALUE = (SELECT MAX([' + #COLUMN_NAME + ']) FROM [' + #TABLE_NAME + ']) '
+ 'WHERE [COLUMN_NAME] = ''' + #COLUMN_NAME + ''' AND TABLE_NAME = ''' + #TABLE_NAME + '''';
PRINT #SQL
EXEC (#SQL)
FETCH NEXT FROM db_cursor INTO #TABLE_NAME, #COLUMN_NAME
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT * FROM #TABLE
DROP TABLE #TABLE
END
GO
Usage:
EXEC GET_COLUMNS_WITH_MAX_VALUE 'INT'
Results:
TABLE1 ID 50
TABLE2 ID 100
TABLE3 CarID 20
TABLE4 StudentID 30
I am trying to write a windows service, which will send automatic emails. all the tables which require email sending have common columns 'templateid' and 'emailstatus'. I want to iterate through all the tables and get the tables which has column name 'templateid'.
Now that i have the list of tables with column name 'templateid' get the data from each table whose email status is 'false' and save it in a temporary table.
if 'table1' has 4 rows of data, the temporary table should have 4 rows. after iterating through the next table the row collection should be added to the same temporary table.
IF (SELECT object_id('TempDB..#TEMPTABLE')) IS NOT NULL
BEGIN
DROP TABLE #TEMPTABLE
END
CREATE TABLE #TEMPTABLE(
[ID] INTEGER IDENTITY(1,1) NOT NULL,
[TABLE_NAME] VARCHAR(1000)
)
INSERT INTO #TEMPTABLE(TABLE_NAME)
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'TEMPLATEID'
SELECT * FROM #TEMPTABLE
DECLARE #ROWCOUNT INT
SET #ROWCOUNT = (SELECT COUNT(ID) FROM #TEMPTABLE)
DECLARE #I INT
SET #I=1
WHILE(#I<=#ROWCOUNT)
BEGIN
DECLARE #TABLENAME VARCHAR(500)
SELECT #TABLENAME=TABLE_NAME FROM #TEMPTABLE WHERE ID=#I
EXEC('SELECT * FROM '+#TABLENAME)
SET #I=#I+1
END
i found the above query which is giving me all the tables. after that i am clueless how to proceed further as i am not good with sql server.
Not sure you are still looking for an answer but the following code will give you a temporary table with just the tables that have a column named 'templateid'. From here you would need a cursor as Tanner suggested to loop through each table and then insert records from each table (into your final target table) where email status = 'false'.
Here is the code that gets you the temp tables with columns named 'templateid' along with a sample for your cursor:
declare #max_tables int
declare #max_columns int
declare #sql nvarchar(400)
declare #x int
declare #y int
declare #table varchar(50)
declare #columns varchar(800)
declare #tablename varchar(100)
create table #c ([Table] varchar(50),[Columns] varchar(800))
select ROW_NUMBER() OVER(ORDER BY name) AS Row, name
into #table_list
from sys.objects
where type_desc = 'USER_TABLE'
order by name
set #max_tables = (select count(*) from sys.objects where type_desc = 'USER_TABLE')
set #y = 0
while #y < #max_tables
begin
set #y = #y + 1
set #table = (select name from #table_list where row = #y)
create table #t (c int)
set #sql = 'select count(*) as c from Information_schema.Columns where table_name = ''' + #table + ''''
insert into #t exec sp_executesql #sql
set #max_columns = (select top 1 c from #t)
DROP TABLE #t
set #x = 0
set #columns = ''
while #x < #max_columns
begin
set #x = #x + 1
set #columns = #columns + (select column_name from Information_schema.Columns where table_name = #table and ordinal_position = #x)
if #x < #max_columns set #columns = #columns + ', '
end
insert into #c select #table,#columns
end
select * into #tables from #c c
where c.Columns like '%templateid%'
declare my_cursor cursor for
select table from #t
open my_cursor
fetch next from my_cursor into #tablename
while ##fetch_status = 0
begin
--do something here to retrieve your data from each table and
--insert into target table
end
close my_cursor
deallocate my_cursor
DROP TABLE #c,#tables,#table_List