I want to pass declared variables to where.
For example I have a table #test:
ID Amount
1 100
2 50
3 20
4 40
5 150
I want to do something like that:
declare #id varchar(11) = '(1, 4, 5)'
select * from #test where IDNumber in #id
How can I do that?
Create a table valued user defined function as given below. There are many examples available online.
Convert comma separated list to Table valued function
this will be giving you good results and better approach, than dynamic sql code.
Once you have the function dbo.split(#string NVARCHAR(4000),',') then use them in the JOIN as given below.
declare #id varchar(11) = '1, 4, 5'
select t.* from #test as t
JOIN dbo.Split(#id,',') AS csv
ON t.id = csv.data;
Try the following-:
declare #id varchar(11) = '(1, 4)'
declare #sql nvarchar(max)
set #sql='select * from TABLE_NAME where id in '+ #id
EXEC sp_sqlexec #sql
SQL Server 2014
As stated in the comments you'd be better off using another datatype.
But if you really did want to do it like your example, you could use dynamic sql:
DECLARE #ids VARCHAR(32) = '1,4,5';
DECLARE #result TABLE (ID INT, Amount INT);
DECLARE #sql NVARCHAR(MAX) =
N' SELECT ID, Amount
FROM #test
WHERE ID IN (' + #ids + ');';
PRINT #sql;
INSERT #result
EXEC(#sql);
SELECT*
FROM #result;
The results are placed into a table variable if you need to use them again in your script, if not you can just EXEC the sql
Related
Does anyone know why this query doesn't work? How to add the table variable itemId as parameter to the exec statement? Thanks
DECLARE #test TABLE
(
itemId UNIQUEIDENTIFIER,
finalAmount DECIMAL
);
INSERT INTO #test EXEC [GetItems]
DECLARE #sql NVARCHAR(max)
DECLARE #param NVARCHAR(max)
SET #param = N'select itemId from #test'
SELECT #sql = 'EXEC [InsertTestItem]'+' ' + #param;
SELECT #sql
EXEC(#sql)
See a full working example in SQL Server, you should be able to run each block one after the other to see that its selected everything from your table type that you pass in to the stored proc
-- Create the Table type that we will use in the stored proc------------------------
IF NOT EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'MyIdTableType')
BEGIN
PRINT 'Creating type [dbo].[MyIdTableType]'
CREATE TYPE [dbo].MyIdTableType AS TABLE (
Id BIGINT
)
END
GO
-- Create a stored proc that uses it ------------------------
CREATE PROCEDURE [dbo].[UsMyTabelType]
#IdsTable AS [dbo].MyIdTableType Readonly
AS
BEGIN
-- Now you have the data you can use it like any normal table and join on it
SELECT * FROM #IdsTable
END
GO
-- Lets test it out ------------------------
DECLARE #myIds AS MyIdTableType
INSERT INTO #myIds (Id)
VALUES
(1),
(2),
(3)
EXEC dbo.UsMyTabelType #IdsTable = #myIds
I want to run:
select Mycalculatefunction('((3*4)-3)*5')
select ('((3*4)-3)*5')
OUTPUT: ((3*4)-3)*5 wrong (not int value)
My desired output is: 45
I defined a stored procedure:
create PROCEDURE dbo.Eval
(#exp varchar(MAX))
AS
SET NOCOUNT ON
DECLARE #SQLString NVARCHAR(MAX)
SET #SQLString = 'SELECT '+#exp
EXEC sp_executesql #SQLString
I call it:
exec dbo.Eval '((3*4)-3)*5'
How can I do in this process is the trigger?
Your SP is vulnerable to injection. F.e. I pass exec dbo.Eval '1;DROP TABLE some_table;'. Better use xml.query:
CREATE PROCEDURE dbo.Eval
#formula nvarchar(max)
AS
DECLARE #sql nvarchar(max)
SELECT #sql = N'
DECLARE #x xml = ''''
SELECT CAST(#x.query('''+#formula+''') as nvarchar(max))'
EXEC sp_executesql #sql
Then
EXEC dbo.Eval '((3*4)-3)*5'
Output:
45
Triggers part (as there were no info about your tables, just general explanation, I add full batch with comments):
--Create table that will store Formulas
CREATE TABLE Formulas (
ID int IDENTITY(1,1) NOT NULL,
Formula nvarchar(max) NULL,
CONSTRAINT PK_ID PRIMARY KEY (ID)
)
GO
--Create table to store results of the formulas
CREATE TABLE Results (
T1_ID int NOT NULL,
Result int NULL
)
GO
--Linked by ID
ALTER TABLE Results ADD CONSTRAINT FK_Formulas_Results FOREIGN KEY (T1_ID)
REFERENCES Formulas (ID)
GO
--Create a Table Valued Parameter
CREATE TYPE FormulaResults AS TABLE (
ID int NOT NULL,
Formula nvarchar(max) NULL
)
GO
--Create a procedure to do the count
CREATE PROCEDURE dbo.GetResults
#TVP FormulaResults READONLY
AS
DECLARE #sql nvarchar(max)
SELECT #sql = N'DECLARE #x xml = '''' '
SELECT #sql = #sql + 'SELECT '+CAST(ID as nvarchar(max))+' as ID, CAST(#x.query('''+Formula+''') as nvarchar(max)) UNION ALL '
FROM #TVP
SELECT #sql = LEFT(#sql,LEN(#sql)-LEN('UNION ALL '))
EXEC sp_executesql #sql
GO
--Create a trigger that will count formula after insert and update
CREATE TRIGGER GetResultsTrigger
ON Formulas
AFTER INSERT, UPDATE
AS
DECLARE #FormulaTVP AS FormulaResults
DECLARE #Results TABLE(
T1_ID int NOT NULL,
Result int NULL
)
INSERT INTO #FormulaTVP
SELECT *
FROM inserted
INSERT INTO #Results
EXEC dbo.GetResults #FormulaTVP
MERGE Results r
USING #Results s
ON r.T1_ID = s.T1_ID
WHEN NOT MATCHED THEN
INSERT VALUES (s.T1_ID, s.Result)
WHEN MATCHED THEN
UPDATE SET Result = s.Result;
After that run:
INSERT INTO [Formulas] VALUES
('1+3'),('2+2*8')
SELECT [ID],
[Formula]
FROM [Test].[dbo].[Formulas]
SELECT [T1_ID],
[Result]
FROM [Test].[dbo].[Results]
Output:
ID Formula
1 1+3
2 2+2*8
T1_ID Result
1 4
2 18
image 1
ALTER FUNCTION [dbo].[Calculate]
( #expression AS VARCHAR(MAX)
)
RETURNS xml
AS
BEGIN
-- routine body goes here, e.g.
-- SELECT 'Navicat for SQL Server'
DECLARE #result xml
declare #x xml=''
--I can not pass as a parameter
select #result=#x.query(('(4*3)*5-10'))
return #result;
END
i call this function:
SELECT CAST(CAST(CAST(dbo.[Calculate]('How do I pass parameters') AS XML) AS VARCHAR(100)) AS DECIMAL(4,2))
Output:
50.00
select #result=#x.query('sql:variable("#expression")')
result: '2+2' :(((
I have a stored procedure which takes 'table name' as parameter. I want to store my 'exec' results to a variable and display using that variable.
Here is my T-SQL stored procedure..
create procedure DisplayTable( #tab varchar(30))
as
begin
Declare #Query VARCHAR(30)
set #Query='select * from ' +#tab
EXEC (#Query)
END
I want to do something like this..
SET #QueryResult = EXEC (#Query)
select #QueryResult
How do i achieve this.. Please help.. I am a beginner..
You can use XML for that. Just add e.g. "FOR XML AUTO" at the end of your SELECT. It's not tabular format, but at least it fulfills your requirement, and allows you to query and even update the result. XML support in SQL Server is very strong, just make yourself acquainted with the topic. You can start here: http://technet.microsoft.com/en-us/library/ms178107.aspx
alter procedure DisplayTable(
#tab varchar(30)
,#query varchar(max) output
)
as
BEGIN
Declare #execution varchar(max) = 'select * from ' +#tab
declare #tempStructure as table (
pk_id int identity
,ColumnName varchar(max)
,ColumnDataType varchar(max)
)
insert into
#tempStructure
select
COLUMN_NAME
,DATA_TYPE
from
INFORMATION_SCHEMA.columns
where TABLE_NAME= #tab
EXEC(#execution)
declare #ColumnCount int = (SELECT count(*) from #tempStructure)
declare #counter int = 1
while #counter <= #ColumnCount
BEGIN
IF #counter = 1
BEGIN
set #query = (SELECT ColumnName + ' ' + ColumnDataType FROM #tempStructure where pk_id= #counter)
END
IF #counter <> 1
BEGIN
set #query = #query + (SELECT ',' + ColumnName + ' ' + ColumnDataType FROM #tempStructure where #counter = pk_id)
END
set #counter = #counter + 1
END
END
When you execute the SP, you'll now get a return of the structure of the table you want.
This should hopefully get you moving.
If you want the table CONTENTS included, create yourself a loop for the entries, and append them to the #query parameter.
Remember to delimit the #query, else when you read it later on, you will not be able to restructure your table.
First of all you have to understand that you can't just store the value of a SELECTon a table in simple variable. It has to be TABLE variable which can store the value of a SELECTquery.
Try the below:
select 'name1' name, 12 age
into MyTable
union select 'name2', 15 union
select 'name3', 19
--declaring the table variable and selecting out of it..
declare #QueryResult table(name varchar(30), age int)
insert #QueryResult exec DisplayTable 'MyTable'
select * from #QueryResult
Hope this helps!
I have the following part of a query:
Where id in (1,2,3) And country in('France','Italy','Spain')
I want to declare 2 variables and do it like:
Where id in (idsVaraible) And country in(countriesVriable)
It is more like substituting sql code in sql code to make my long query readable and more useful, is there any way to do this?
I think it's more like eval in java script.
Well if you need to pass these sets in as strings, one way would be dynamic SQL:
DECLARE #ids VARCHAR(32) = '1,2,3';
DECLARE #countries VARCHAR(2000) = 'France,Italy,Spain';
DECLARE #sql NVARCHAR(MAX) = N'SELECT ... FROM ...
WHERE id IN (' + #ids + ') AND country IN ('''
+ REPLACE(#countries, ',',''',''') + ''');';
PRINT #sql;
-- EXEC sp_executesql #sql;
Another way would be table-valued parameters. First create these types in your database:
CREATE TYPE dbo.TVPids AS TABLE(ID INT);
CREATE TYPE dbo.TVPcountries AS TABLE(Country VARCHAR(255));
Now your stored procedure can take these types as input:
CREATE PROCEDURE dbo.whatever
#i dbo.TVPids READONLY,
#c dbo.TVPcountries READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT ... FROM dbo.yourtable AS t
INNER JOIN #i AS i ON i.ID = t.ID
INNER JOIN #c AS c ON c.country = t.country;
END
GO
Now your app can pass these two parameters in as sets (e.g. from a DataTable) instead of building a comma-separated string or handling multiple parameters.
Please try using temp table variables:
DECLARE #tblID as TABLE(ID INT)
DECLARE #tblCountry as TABLE(Country NVARCHAR(50))
INSERT INTO #tblID VALUES (1),(2),(3)
INSERT INTO #tblCountry VALUES ('France'),('Italy'),('Spain')
WHERE id in (select ID from #tblID) And country in(select Country from #tblCountry)
I have situation that I have a table in the structure
ID, name
1, 'value1'
1, 'value2'
2, 'value3'
2, 'value4'
1, 'value5'
I wanted to show the above data in following format
id , combineName
1 ,'value1','value2', 'value5'
2 ,'value3','value4'
Is there an easy way to do this in SQL Server 2005, or will I have to run cursors to do it?
Assuming your data is in aTable:
create FUNCTION toCSV (#id int)
RETURNS varchar(100)
AS
BEGIN
DECLARE #List varchar(100)
SELECT #List = COALESCE(#List + ', ', '') +
CAST(name AS varchar(10))
FROM aTable
WHERE ID = #id
RETURN(#list)
END;
go
Then:
select distinct id, dbo.toCSV(id) from aTable
SQL 2005 has a PIVOT function that should do what you want.
http://msdn.microsoft.com/en-us/library/ms177410.aspx
You can do this using nested selects, or more easily using the pivot operator, although you have to know all of the possible values before hand.
If you want it to be dynamic, then you will need a cursor and some dynamic SQL.
Simple Example of COALESCE Function:
Created one Temp table in which i have put one 9 rows with the help of WHILE loop.
The at the Main part i have just take Column to COALESCE function.
DROP TABLE #Material
SET NOCOUNT ON
CREATE TABLE #Material
(
MaterialID INT
)
DECLARE #LoopCounter INT
DECLARE #MaxLoopCounter INT
SET #LoopCounter = 1
SET #MaxLoopCounter = 10
WHILE (#LoopCounter < #MaxLoopCounter)
BEGIN
INSERT INTO #Material (MaterialID) VALUES (#LoopCounter)
SET #LoopCounter = #LoopCounter + 1
END
/* MAIN PART */
DECLARE #MaterialID VARCHAR(100)
SELECT #MaterialID = COALESCE(#MaterialID + ',','') + CAST(MaterialID AS VARCHAR(100)) FROM #Material
PRINT 'FINAL OUTPUT: '+ #MaterialID
-- SELECT * FROM #Material
SET NOCOUNT OFF