Select from multiple table (passed by another select) - sql

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='')

Related

How to compare String Variable with Integer

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

Dynamically alias columns from a view query SQL

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

How to Fill Table Data based on Condition in SQL Server

My Tables are defined like below:
UserData (ColA, ColB, ColC) - This table fills by .CSV file.
These column names are not fixed and number of Table Columns varies in different .CSV files depending on the customer giving the .CSV file.
UserDataDSU (ColD, ColE, ColF, ColG, ColH, ColI, ColJ)
Now, I have to fill UserDataDSU table with UserData table data like below.
If UserData(ColC) exists and it has data, then fill UserDataDSU(ColD) else set ColD as NULL
If UserData(ColA) exists and it has data, then fill UserDataDSU(ColE) else set ColE as NULL
If UserData(ColB) exists and it has data, then fill UserDataDSU(ColF) else set ColF as NULL
Of course, for all the remaining columns in UserDataDSU (like ColG, ColH, ColI, ColJ does not have data in its couter table - UserData, all those should be filled by NULLs.
Please remember that for some other .CSV file got from another customer DATA MAY EXISTS FOR SOME OR ALL OF THESE COLUMNS
Can anyone please suggest how to do this inside a Stored procedure.
TLDR
You can use sys.objects to generate a match the columns between tables based on your business logic and then use this mapping to create a dynamic INSERT sql script.
Below is the SQL script for all this
DECLARE #sql varchar(max) -- will be used for holding dynamic SQL script
-- this temp table will hold the mapping
CREATE TABLE #temp (DColName varchar(100), SColName varchar(100), OrderCol int)
--inserting mapping into temp table based on business logic
INSERT INTO #temp
SELECT
Dest.name,
Source.name,
Dest.object_id -- ordering criteria to generate accurate mapping in script
FROM
sys.columns Dest LEFT JOIN
(
SELECT
name,
CASE
WHEN name='ColC' THEN 'ColD'
WHEN name='ColA' THEN 'ColE'
WHEN name='ColB' THEN 'ColF'
ELSE name
END as Newname -- business logic for matching
FROM
sys.columns
WHERE
object_id IN (
SELECT object_id FROM sys.tables WHERE name ='UserData'
)
)source
ON Dest.Name=Source.NewName
WHERE
Dest.object_id IN (
SELECT object_id
FROM sys.tables
WHERE name ='UserDataDSU'
)
--create the dynamic SQL
SELECT #sql =
'INSERT INTO UserDataDSU ('+
--insert column list of destination table
STUFF((SELECT ','+ Dcolname FROM #temp WHERE Scolname IS NOT NULL ORDER BY OrderCol ASC FOR XML PATH('')),1,1,'') +
') SELECT '+
--insert column list of source table
STUFF((SELECT ','+ Scolname FROM #temp ORDER BY OrderCol ASC FOR XML PATH('')),1,1,'') +
' FROM UserData'
-- execute the dynamic SQL
EXEC(#sql)
-- now drop the temp table
DROP TABLE #temp
Please note that I tested this and this worked for me.
CREATE INSERT table scripts used are below
create table UserData (ColA varchar(100), ColB varchar(100), ColC varchar(100));
insert into UserData values ('A1','B1','C1'),('A2','B2','C2');
create table UserDataDSU (ColD varchar(100), ColE varchar(100), ColF varchar(100), ColG varchar(100), ColH varchar(100), ColI varchar(100), ColJ varchar(100));

SQL if #name exists select ID else insert #name into table

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.

SQL Server SELECT into existing table

I am trying to select some fields from one table and insert them into an existing table from a stored procedure. Here is what I am trying:
SELECT col1, col2
INTO dbo.TableTwo
FROM dbo.TableOne
WHERE col3 LIKE #search_key
I think SELECT ... INTO ... is for temporary tables which is why I get an error that dbo.TableTwo already exists.
How can I insert multiple rows from dbo.TableOne into dbo.TableTwo?
SELECT ... INTO ... only works if the table specified in the INTO clause does not exist - otherwise, you have to use:
INSERT INTO dbo.TABLETWO
SELECT col1, col2
FROM dbo.TABLEONE
WHERE col3 LIKE #search_key
This assumes there's only two columns in dbo.TABLETWO - you need to specify the columns otherwise:
INSERT INTO dbo.TABLETWO
(col1, col2)
SELECT col1, col2
FROM dbo.TABLEONE
WHERE col3 LIKE #search_key
There are two different ways to implement inserting data from one table to another table.
For Existing Table - INSERT INTO SELECT
This method is used when the table is already created in the database earlier and the data is to be inserted into this table from another table. If columns listed in insert clause and select clause are same, they are not required to list them. It is good practice to always list them for readability and scalability purpose.
----Create testable
CREATE TABLE TestTable (FirstName VARCHAR(100), LastName VARCHAR(100))
----INSERT INTO TestTable using SELECT
INSERT INTO TestTable (FirstName, LastName)
SELECT FirstName, LastName
FROM Person.Contact
WHERE EmailPromotion = 2
----Verify that Data in TestTable
SELECT FirstName, LastName
FROM TestTable
----Clean Up Database
DROP TABLE TestTable
For Non-Existing Table - SELECT INTO
This method is used when the table is not created earlier and needs to be created when data from one table is to be inserted into the newly created table from another table. The new table is created with the same data types as selected columns.
----Create a new table and insert into table using SELECT INSERT
SELECT FirstName, LastName
INTO TestTable
FROM Person.Contact
WHERE EmailPromotion = 2
----Verify that Data in TestTable
SELECT FirstName, LastName
FROM TestTable
----Clean Up Database
DROP TABLE TestTable
Ref 1 2
It would work as given below :
insert into Gengl_Del Select Tdate,DocNo,Book,GlCode,OpGlcode,Amt,Narration
from Gengl where BOOK='" & lblBook.Caption & "' AND DocNO=" & txtVno.Text & ""
If the destination table does exist but you don't want to specify column names:
DECLARE #COLUMN_LIST NVARCHAR(MAX);
DECLARE #SQL_INSERT NVARCHAR(MAX);
SET #COLUMN_LIST = (SELECT DISTINCT
SUBSTRING(
(
SELECT ', table1.' + SYSCOL1.name AS [text()]
FROM sys.columns SYSCOL1
WHERE SYSCOL1.object_id = SYSCOL2.object_id and SYSCOL1.is_identity <> 1
ORDER BY SYSCOL1.object_id
FOR XML PATH ('')
), 2, 1000)
FROM
sys.columns SYSCOL2
WHERE
SYSCOL2.object_id = object_id('dbo.TableOne') )
SET #SQL_INSERT = 'INSERT INTO dbo.TableTwo SELECT ' + #COLUMN_LIST + ' FROM dbo.TableOne table1 WHERE col3 LIKE ' + #search_key
EXEC sp_executesql #SQL_INSERT
select *
into existing table database..existingtable
from database..othertables....
If you have used select * into tablename from other tablenames already, next time, to append, you say select * into existing table tablename from other tablenames
IF you want a identity column in new table created with select into then it can be done as below.
SELECT
ID = IDENTITY(INT, 1, 1),
name
INTO table2
FROM table1
If you want to insert into Table_A, from Table_B, only if the column is not in Table_A, then use the following:
BEGIN TRANSACTION
INSERT INTO dbo.Table_A (Column_1)
SELECT DISTINCT Some_Column AS Column_1
FROM dbo.Table_B
WHERE Some_Column
NOT IN (SELECT DISTINCT GroupId
FROM dbo.Table_A)
COMMIT