How to Fill Table Data based on Condition in SQL Server - sql

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));

Related

Select from multiple table (passed by another select)

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

Inserting a Row of Default Values into a Temporary Table

I'm attempting to select a row of default values from a table. However, I don't want to create a new row in my original table. My original table has non-null default values (all blanks or zeros) defined for all columns (except for the one unique identifier). I begin by creating the temporary table:
SELECT
TOP 0 *
INTO
#Table
FROM
Database.dbo.Table
Then I examine the empty table:
SELECT
*
FROM
#Table
Everything looks fine so far. There are no rows, but I can see all the columns from my original table. Then, I attempt to insert a single row into the table with default values for all the columns:
INSERT INTO
#Table
DEFAULT VALUES
Rather than success, I get the following error:
Cannot insert the value NULL into column 'Column',
table 'tempdb.dbo.#Table___0001A';
column does not allow nulls. INSERT fails.
I next tried to insert a row with just one field defined.
INSERT INTO
#Table
(Column)
VALUES
('Value')
Same results. It appears that the definitions of the column default values from my original table were not included in the creation of the temporary table. Any suggestions?
When you create a temp table via SELECT ... INTO #Table the temp table gets all columns from the main table, but no constraints or indexes.
Obviously, you can explicitly create temp table with all necessary constraints.
One more option is to actually insert a row into the main table, let the engine populate it with default values, then read inserted values and insert them into the temp table. All this in a transaction. Then rollback the transaction, so that the main table remains as it was.
To make it work you need to use table variable instead of temp table, though, because temp tables participate in transactions as normal tables, but table variables don't. It means that you have to define the table variable in advance, so you need to know what columns your original table has. But, at least, you don't have to know the definition of default constraints.
Also, if your main table has an INDENTITY column, this insert-rollback will create a gap in identity values.
Sample table
CREATE TABLE [dbo].[MainTable](
[Col1] [int] NOT NULL,
[Col2] [nvarchar](50) NOT NULL,
[Col3] [date] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[MainTable] ADD CONSTRAINT [DF_MainTable_Col1]
DEFAULT ((123)) FOR [Col1]
GO
ALTER TABLE [dbo].[MainTable] ADD CONSTRAINT [DF_MainTable_Col2]
DEFAULT ('qwerty') FOR [Col2]
GO
ALTER TABLE [dbo].[MainTable] ADD CONSTRAINT [DF_MainTable_Col3]
DEFAULT (getdate()) FOR [Col3]
GO
Query
DECLARE #T TABLE (Col1 int, Col2 nvarchar(50), Col3 date);
BEGIN TRANSACTION;
INSERT INTO dbo.MainTable
OUTPUT inserted.Col1, inserted.Col2, inserted.Col3
INTO #T (Col1, Col2, Col3)
DEFAULT VALUES;
ROLLBACK TRANSACTION;
SELECT *
FROM #T;
Result
+------+--------+------------+
| Col1 | Col2 | Col3 |
+------+--------+------------+
| 123 | qwerty | 2017-08-29 |
+------+--------+------------+
You need to create your temp table and include the default definitions in it.
--Check to see if table exists
--If it does, drop it
IF OBJECT_ID('tempdb.dbo.#Table', 'U') IS NOT NULL
DROP TABLE #Table
--Create temp table with default value
CREATE TABLE #Table
(
columnA INT DEFAULT (1),
columnB INT DEFAULT (2),
columnC INT DEFAULT (3)
)
--Insert a row of default values
INSERT INTO
#Table
DEFAULT VALUES
--See it
SELECT *
FROM #Table
--Drop temp table after you are done
DROP TABLE #Table
Build your row from the temptdb catalog?
SELECT c.name AS 'Colunmn'
, TYPE_NAME(c.user_type_id) AS 'Type'
, CASE c.is_nullable WHEN 0 THEN 'No Nulls'
ELSE '' END AS 'Nullable'
, CASE c.default_object_id WHEN 0 THEN ''
ELSE 'Y' END AS 'Has_Default'
, dft.definition as Default_Value
, CASE ISNULL(c.max_length, -1) WHEN -1 THEN 'Variable'
ELSE CAST(c.max_length AS VARCHAR) END AS 'Length'
, ISNULL('['+OBJECT_NAME(fkc.referenced_object_id)+'].['+Cref.name+']', ' ') AS ForeignKeyInto
FROM tempdb.sys.tables t
JOIN tempdb.sys.columns c ON t.object_id = c.object_id
LEFT JOIN tempdb.sys.foreign_key_columns FKC ON c.object_id = fkc.Parent_object_id
AND fkc.parent_column_id = c.column_id
LEFT JOIN tempdb.sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
left join tempdb.sys.default_constraints dft on c.default_object_id = dft.object_id
WHERE t.name like '#temp%'
ORDER BY t.name
, c.name;

Compare Column names from 2 diff table in diff db in MS SQL

I am trying to get column names from 2 diff tables in diff db and compare them to see if there is any extra column in any table. They should match exactly. One possible solution could be getting all the column names from both table and dump in a temp table side by side and compare? Pls help.
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL DROP TABLE #myTable
CREATE table #myTable (
table1 varchar(100) null,
table2 varchar(100) null
)
INSERT INTO #myTable (table1)
SELECT name
FROM sys.columns
WHERE object_id = OBJECT_ID('table1')
select * from #mytable
DROP TABLE #mytable
I modified your query to this
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL DROP TABLE #myTable
CREATE table #myTable
(
rowNum int IDENTITY(1,1),
table1 varchar(100) null
)
GO
IF OBJECT_ID('tempdb..#myTable2') IS NOT NULL DROP TABLE #myTable2
CREATE table #myTable2
(
rowNum int IDENTITY(1,1),
table2 varchar(100) null
)
GO
USE database1 --your 1st database name here
GO
INSERT INTO #myTable (table1)
(
SELECT
name
FROM sys.columns
WHERE object_id = OBJECT_ID('Table_1'))
GO
USE database2 -- your 2nd database name here
GO
INSERT INTO #myTable2 (table2)
(
SELECT
name
FROM sys.columns
WHERE object_id = OBJECT_ID('Table_2'))
GO
SELECT table1,table2
FROM #myTable m
FULL OUTER JOIN #myTable2 m2 ON m.rowNum = m2.rowNum
ORDER BY table1,table2
DROP TABLE #mytable
DROP TABLE #mytable2

SQL - Table Type / passing a table as a paramater

I have a stored procedure that takes in a table as a parameter.
For example: I have a type PartsImport:
CREATE TYPE PartsImport AS TABLE
(
Number_Key varchar(10),
LogDate smalldatetime,
FullName varchar(125),
Descrip varchar(250)
);
Then the stored procedure takes in this param:
#PTable PartsImport ReadOnly
The stored procedure does an insert into a table via a simple select * from #PTable, but now I need to join this table variable with other tables when creating the select statement, but I always get an error message
Must declare the scalar variable "#PPTable"
How do you select an individual column from this #PTable? I tried #PTable.LogDate, but it doesn't like the syntax. Is it possible to use the variable table in a join and select the columns or does it only work with select * ?
You can try using an Alias to refer to your table, instead of the variable name. For example:
SELECT P.LogDate FROM #PTable AS P
try with below example, when you fetch column only from table variable then works fine but when you use in join you must use alias name with table variable name.
CREATE TYPE PartsImport AS TABLE
(
Number_Key varchar(10),
LogDate smalldatetime,
FullName varchar(125),
Descrip varchar(250)
);
create table PartsImportother (col1 varchar(10), col2 varchar(3))
insert into PartsImportother values('1','ads')
Declare #table PartsImport
insert into #table(Number_Key,LogDate,FullName,Descrip) values('1','01-01-2015','aaa','adsfadfa')
-- select [specific column] from [only table variable]
select Number_Key from #table
-- select [specific column] from [table variable with join]
select T.Number_Key from #table as T inner join PartsImportother on T.Number_Key = PartsImportother.col1

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