How can I use dynamic SQL to query a table, and then use one of the results to alias a column?
I'm trying something like:
SELECT
ID, ModelName INTO #tmpTable
FROM Models
And then:
SELECT
ModelNumber AS (SELECT ModelName FROM #tmpTable)
FROM NewModels
For those asking for more detail:
We have a view that contains everything we want, but the columns are IDs like "def123". In another table we have the names that resolve the IDs like "def123", "FName". We want to query the view but have the name appear (using AS) instead of the ID. Essentially, we want to query the definitions table in the AS statement to get dynamic naming.
Do not try to bend the dynamic SQL, only realize the truth of it, there is no need for it...
A ModelName by another other ModelNumber will still smell the same ...
#IMissSQLQuotes
select ID
, ModelName as ModelNumber
from NewModels
One possible path to consider would be to replace alias names in a dynamic sql.
Based on a table with the new alias names.
Example snippet:
IF OBJECT_ID('tempdb..#NewModels') IS NOT NULL DROP TABLE #NewModels;
CREATE TABLE #NewModels (ModelNumber int, ModelType char(1));
INSERT INTO #NewModels (ModelNumber, ModelType) values
(100, 'A'),
(101, 'B'),
(102, 'C');
IF OBJECT_ID('tempdb..#tmpModelNames') IS NOT NULL DROP TABLE #tmpModelNames;
CREATE TABLE #tmpModelNames (Code varchar(30) primary key, ModelName varchar(30));
INSERT INTO #tmpModelNames (Code, ModelName) values
('Col1', 'Model Name 1'),
('Col2', 'Model Name 2');
DECLARE #Sql NVARCHAR(max) = 'SELECT
ModelNumber AS [Col1],
ModelType AS [Col2]
FROM #NewModels
WHERE ModelNumber = #ModelNumber';
select #Sql = replace(#Sql, quotename(Code), quotename(ModelName)) from #tmpModelNames;
--select #Sql as Sql;
EXECUTE sp_executesql #Sql, N'#ModelNumber int', #ModelNumber = 101;
Returns:
Model Name 1 Model Name 2
------------ -------------
101 B
Related
I have this table structure and and some sample data. I want return data for multiple ids via parameter. I have declared a parameter string and now I want to compare it with the column but it ain't allowing because ID is integer.
Can anybody give me any help here ?
CREATE TABLE EMPLOYEE
(
ID INT,
EMPLOYEE_NAME VARCHAR(50)
);
INSERT INTO EMPLOYEE VALUES (1, 'Isaac Frempong');
INSERT INTO EMPLOYEE VALUES (2, 'Eric Ortizz');
DECLARE #StrID VARCHAR(20) = '1, 2'
SELECT * FROM EMPLOYEE
WHERE ID = #StrID
SELECT * FROM EMPLOYEE
WHERE #StrID+',' LIKE '%'+cast(ID as varchar(20))+'%,'
Pretty bad performance as it will need to do a table scan but safe enough.
Generally though, your list of IDs should be a table variable you can do a proper JOIN or IN with
The easiest solution is to use dynamic SQL
DECLARE #sql VARCHAR(1000) = 'SELECT * FROM EMPLOYEE WHERE ID IN (' + #StrID + ')';
EXEC(#sql);
For SQL Server 2017+ you could use STRING_SPLIT a table-valued function that splits a string into rows of substrings
CREATE TABLE EMPLOYEE
(
ID INT,
EMPLOYEE_NAME VARCHAR(50)
);
INSERT INTO EMPLOYEE VALUES (1, 'Isaac Frempong');
INSERT INTO EMPLOYEE VALUES (2, 'Eric Ortizz');
DECLARE #StrID VARCHAR(20) = '1, 2'
SELECT * FROM EMPLOYEE
WHERE ID IN (SELECT value FROM STRING_SPLIT (#StrID,','))
Refer this working fiddle
Create a user defined table type and pass it as a parameter.
CREATE TYPE [UDT_INTIDS] AS TABLE(
[ID] [int] NOT NULL
)
GO
-- create a table value
DECLARE #IDs [UDT_INTIDS];
INSERT #IDs VALUES (1),(2);
-- search using table value.
SELECT e.*
FROM EMPLOYEE e
WHERE e.ID IN (SELECT p.ID FROM #IDs p);
-- or
SELECT e.*
FROM EMPLOYEE e
JOIN #IDs p ON e.ID = p.ID;
See https://learn.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine?view=sql-server-2017 for more details.
You can use the Cast in SQL-Server to cast it to the appropriate datatype. Source Here
WHERE CAST(ID AS VARCHAR(20)) = #StrID
Alternatively: You can use CONVERT function.
WHERE CONVERT(VARCHAR(20), ID) = #StrID
Question updated.
What I want to achive is to get list of new tables which are empty or null in description field. (new tables means with prefix new_) and all tables have description field.
Table definition:
create table topic (id int, description varchar(255));
create table comment (id int, description varchar(255));
create table author (id int, description varchar(255));
create table new_topic (id int, description varchar(255));
create table new_comment (id int, description varchar(255));
create table new_author (id int, description varchar(255));
Sample data and description:
insert into new_topic (id, description) values (1, null);
insert into new_topic (id, description) values (2, 'This is topic description');
insert into new_comment (id, description) values (1, null);
insert into new_comment (id, description) values (2, null);
insert into new_author (id, description) values (1, 'This is casual first author.');
insert into new_author (id, description) values (2, 'This is casual second author.');
Like you can notice on my example ideal output for my sample data would've be:
table_name:
new_topic
new_comment
My actual solution works, but I need to manually add tables and I make a lot of repetitions.
select distinct 'new_topic' as table_name
from new_topic where description is null
select distinct 'new_comment' as table_name
from new_comment where description is null
select distinct 'new_author' as table_name
from new_author where description is null
And output of my solution is like below:
table_name
new_topic
table_name
new_comment
table_name
I also created SELECT to get all new tables:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'new_%' AND TABLE_TYPE = 'BASE TABLE'
Which could've be an entry point for my previous select, but I don't know how to connect those two.
Also my solution is avaiable on dbfiddle
Oh I think I understand what you are after. Yes this requires dynamic sql. Also, please note that your query to find all tables with a name like new_ is not quite right. The underscore is a wildcard pattern check. So that would return a table named "news" when you don't want it to. Wrap the underscore in square brackets to solve this. Here is how I would go about this type of query. The comments in the code should explain this.
declare #SQL nvarchar(max) = '' --this must be initialized to an empty string for this to work.
select #SQL = #SQL + 'select distinct TableName = ''' + t.name + ''' from ' + quotename(t.name) + ' where description is null union all '
from sys.tables t
where name like 'new[_]%' --need the square brackets because the underscore is a wildcard so you might get false positives
select #SQL = left(#SQL, len(#SQL) - 10)
--this will show you the dynamic sql
select #SQL
--once you are satisfied the dynamic sql is correct uncomment the next line to execute it
--exec sp_executesql #SQL
Could you not just do:-
select table_name from information_schema.columns
where table_name like 'prefix_%' and (column_name is null or column_name='')
Table looks like below:
CREATE TABLE names
(ID int,
name varchar(10) unique)
I need to achieve the following result:
if #name not exists in names then insert into names (name) values (#name)
select id from names where name=#name
It would be best to achieve it with user defined function.
You basically have the answer written in your question already:
IF (NOT EXISTS (SELECT * FROM names WHERE name = #name))
INSERT INTO names (name) values (#name);
SELECT id FROM names WHERE name = #name;
The only problem is that you haven't set up your table names to use an IDENTITY column. This means you need to assign values for id as well.
I have a stored procedure that returns 6 columns. But I want to take only 2 columns and insert them into my table variable.
DECLARE #CategoryTable TABLE(
CategoryId Int NOT NULL,
Name nvarchar(255) NOT NULL
)
INSERT INTO #CategoryTable EXEC [GetAllTenantCategories] #TenantId
When I run this
Column name or number of supplied values does not match table
definition
How to insert only specified columns from a stored procedure?
I do not want to use SELECT INTO as it is not supported by SQL Azure
Tried below and got Invalid object name '#Temp'
DECLARE #CategoryTable TABLE(
CategoryId Int NOT NULL,
Name nvarchar(255) NOT NULL
)
INSERT INTO #Temp EXEC [GetAllTenantCategories] 1
INSERT INTO #CategoryTable (CategoryId, Name)
SELECT CategoryId, Name from #Temp
DROP TABLE #Temp
You can create a temp table first and the INSERT the required columns in your table variable.
CREATE TABLE #temp
(
your columns and datatype
)
INSERT INTO #temp
EXEC [GetAllTenantCategories] #TenantId
Then you can,
DECLARE #CategoryTable TABLE(
CategoryId Int NOT NULL,
Name nvarchar(255) NOT NULL
)
INSERT INTO #CategoryTable (CategoryId, Name)
select CategoryId, Name from #temp
Also drop the #temp table,
DROP TABLE #temp
Refer the points taken from https://www.simple-talk.com/sql/performance/execution-plan-basics/
When the Estimated Plan is Invalid
In some instances, the estimated plan won't work at all. For example, try generating an estimated plan for this simple bit of code:
CREATE TABLE TempTable
(
Id INT IDENTITY (1 , 1 )
,Dsc NVARCHAR (50 )
);
INSERT INTO TempTable ( Dsc )
SELECT [Name]
FROM [Sales] .[Store] ;
SELECT *
FROM TempTable ;
DROP TABLE TempTable ;
You will get this error:
Invalid object name 'TempTable'.
The optimizer, which is what is used to generate Estimated Execution plans, doesn't execute T-SQL.
It does run the stateĀments through the algebrizer , the process outlined earlier that is responsible for verifying the names of database objects. Since the query has not yet been executed, the temporary table does not yet exist. This is the cause of the error.
Running this same bit of code through the Actual execution plan will work perfectly fine.
Hope you got why your temp table approach not worked :) Because you might tried as T-SQL
We can use OPENQUERY
SELECT EmployeeID,CurrentSalary INTO #tempEmp
FROM OPENQUERY(LOCALSERVER,'Exec TestDB.dbo.spEmployee')
I want to set a variable as a string of values. E.g.
declare #FirstName char(100)
select #FirstName = 'John','Sarah','George'
SELECT *
FROM Accounts
WHERE FirstName in (#FirstName)
I'm getting a syntax error in the line select #FirstName = 'John','Sarah','George':
Incorrect syntax near ','
Is there any way I can set the variable with many values?
declare #tab table(FirstName varchar(100))
insert into #tab values('John'),('Sarah'),('George')
SELECT *
FROM #tab
WHERE 'John' in (FirstName)
You're trying to assign three separate string literals to a single string variable. A valid string variable would be 'John, Sarah, George'. If you want embedded single quotes between the double quotes, you have to escape them.
Also, your actual SELECT won't work, because SQL databases won't parse the string variable out into individual literal values. You need to use dynamic SQL instead, and then execute that dynamic SQL statement. (Search this site for dynamic SQL, with the database engine you're using as the topic (as in [sqlserver] dynamic SQL), and you should get several examples.)
-- create test table "Accounts"
create table Accounts (
c_ID int primary key
,first_name varchar(100)
,last_name varchar(100)
,city varchar(100)
);
insert into Accounts values (101, 'Sebastian', 'Volk', 'Frankfurt' );
insert into Accounts values (102, 'Beate', 'Mueller', 'Hamburg' );
insert into Accounts values (103, 'John', 'Walker', 'Washington' );
insert into Accounts values (104, 'Britney', 'Sears', 'Holywood' );
insert into Accounts values (105, 'Sarah', 'Schmidt', 'Mainz' );
insert into Accounts values (106, 'George', 'Lewis', 'New Jersey' );
insert into Accounts values (107, 'Jian-xin', 'Wang', 'Peking' );
insert into Accounts values (108, 'Katrina', 'Khan', 'Bolywood' );
-- declare table variable
declare #tb_FirstName table(name varchar(100));
insert into #tb_FirstName values ('John'), ('Sarah'), ('George');
SELECT *
FROM Accounts
WHERE first_name in (select name from #tb_FirstName);
SELECT *
FROM Accounts
WHERE first_name not in (select name from #tb_FirstName);
go
drop table Accounts;
go
A quick way to turn your varchar variable to a table (array of values) is to have your FirstName variable as a whole varchar first and then use the STRING_SPLIT method.
declare #FirstName varchar(100)
select #FirstName = 'John,Sarah,George'
SELECT *
FROM Accounts
WHERE FirstName in (SELECT * FROM STRING_SPLIT(#FirstName, ','))
In SQL you can not have a variable array.
However, the best alternative solution is to use a temporary table.
I just want to extend #Code Save's answer
--collection table is required, since we cannot use directly arrays in TSQL
declare #CollectionTable table(FirstName varchar(100))
insert into #CollectionTable values('John'),('Sarah'),('George')
SELECT * FROM TargetTable
WHERE Name IN (SELECT * FROM #CollectionTable)
In this way we can use the result from the SELECT statement from our #CollectionTable to be evaluated in the IN operator. And of course we can re-use the #CollectionTable as many times as we need.