Dynamically created Tables JOIN in SQL Server - sql

I have 3 types of tables
Major table as follows
CREATE TABLE #InitialTable
(
Id int PRIMARY KEY IDENTITY(1,1),
RP varchar(20)
)
INSERT INTO #InitialTable
VALUES ('R1', 'R2', 'R3')
GO
Table contains dynamically created tables information as follows
CREATE TABLE #DynamicTablesInfo
(
Id int PRIMARY KEY IDENTITY(1,1),
RPId int FOREIGN KEY REFERENCES #InitialTable(Id),
TableName varchar(100)
)
GO
INSERT INTO #DynamicTablesInfo
VALUES (1, 'Table_X1'), (2, 'Table_X2'), (3, 'Table_X3')
GO
Dynamically created tables these tables can be any number of tables and the tables info is available in above table.
CREATE TABLE #Table_X1
(
Id int PRIMARY KEY IDENTITY,
Version_Value varchar(100)
)
GO
INSERT INTO #Table_X1
VALUES ('Val_X1_1'), ('Val_X1_2'), ('Val_X1_3')
GO
CREATE TABLE #Table_X2
(
Id int PRIMARY KEY IDENTITY,
Version_Value varchar(100)
)
GO
INSERT INTO #Table_X2
VALUES ('Val_X2_1'), ('Val_X2_2'), ('Val_X2_3')
GO
CREATE TABLE #Table_X3
(
Id int PRIMARY KEY IDENTITY,
Version_Value varchar(100)
)
GO
INSERT INTO #Table_X3
VALUES ('Val_X3_1'), ('Val_X3_2'), ('Val_X3_3')
GO
Now I wanted to join InitialTable with dynamically created tables (Table_X1, Table_X2, Table_X3,....) with the help of DynamicTablesInfo table - how to do that?
Note: for easy update, delete, insert I created them as temporary tables but in my application all are real tables.

Instead of doing this:
CREATE TABLE #Table_X1
(
Id int PRIMARY KEY IDENTITY
,Version_Value varchar(100)
)
GO
CREATE TABLE #Table_X2
(
Id int PRIMARY KEY IDENTITY
,Version_Value varchar(100)
)
GO
CREATE TABLE #Table_X3
(
Id int PRIMARY KEY IDENTITY
,Version_Value varchar(100)
)
GO
Do this one time:
CREATE TABLE Table_X
(
Id int PRIMARY KEY IDENTITY
,Version_Value varchar(100)
,X_number INT
)
GO
Then instead of doing this:
INSERT INTO #Table_X1 VALUES ('Val_X1_1'),('Val_X1_2'),('Val_X1_3')
INSERT INTO #Table_X2 VALUES ('Val_X2_1'),('Val_X2_2'),('Val_X2_3')
INSERT INTO #Table_X3 VALUES ('Val_X3_1'),('Val_X3_2'),('Val_X3_3')
Do this:
INSERT INTO Table_X VALUES ('Val_X1_1',1),('Val_X1_2',1),('Val_X1_3',1)
INSERT INTO Table_X VALUES ('Val_X2_1',2),('Val_X2_2',2),('Val_X2_3',2)
INSERT INTO Table_X VALUES ('Val_X3_1',3),('Val_X3_2',3),('Val_X3_3',3)
Much easier to query without dynamics:
--no
SELECT * FROM Table_X1
--yes
SELECY * FROM Table_X WHERE X_Number = 1
You've indicated you're stuck with it how it is, so you'll need to create and run your queries dynamically too. This is c#/vb flavored pseudocode:
string sql = "SELECT * FROM sometable"
for int x = 1 to 3
sql = sql + " table_x{x} on sometable.id = table_x{x}.id"
Or perhaps build a Union:
string sql = "WITH allx AS (SELECT * FROM table_x1"
for int x = 2 to 10
sql = sql + " UNION ALL SELECT * FROM table_x{x}"
sql = sql + ") select * from sometable inner join allx on..."
But I echo larnu's sentiments in the comments.. if you truly cannot change the tables that are created, consider creating a VIEW in a similar way to the UNION code above, that will sit alongside X number of tables and will provide a way to query without dynamic:
CREATE VIEW AllX AS(
SELECT x.*, 1 as Which FROM TABLE_X1 x
UNION ALL SELECT x.*, 2 as Which FROM TABLE_X2 x
UNION ALL SELECT x.*, 3 as Which FROM TABLE_X3 x
...
Use the same technique that creates 10 tables to string together a CREATE VIEW statement that views over the 10 tables, then you can query the view without Dynamic sql generation

Related

Generate ID for duplicate values in sql server

I found following link to assign identical ID to duplicates in SQL server,
my understanding there is no sql server function to automatically generate it rather than using insert and update queries in link attached, is that statement True, if yes, then what would be the trigger if for example someone insert data to MyTable then run insert and update query from link:
Assign identical ID to duplicates in SQL server
INSERT INTO secondTable (word) SELECT distinct word FROM MyTable;
UPDATE MyTable SET ID = (SELECT id from secondTable where MyTable.word = secondTable.word)
thanks,
S
Is this what you want? I can't think of an "automatic" solution that would just increase the Id for new words.
CREATE TABLE MyTable (
Id INT NOT NULL,
Word NVARCHAR(255) NOT NULL
PRIMARY KEY (Id, Word)); -- primary key will make it impossible to have more than one combination of word and id
DECLARE #word NVARCHAR(255) = 'Hello!';
-- Get existing id or calculate a new id
DECLARE #Id INT = (SELECT Id FROM MyTable WHERE Word = #word);
IF(#id IS NULL) SET #Id = (SELECT MAX(Id) + 1 FROM MyTable);
INSERT INTO MyTable (Id, Word)
VALUES (#id, #word)
SELECT * FROM MyTable
If you can't for some reason have id and word as a combined primary key, you may use an unique index to make sure that there is only one combination

How to split data in SQL Server table row

I have table of transaction which contains a column transactionId that has values like |H000021|B1|.
I need to make a join with table Category which has a column CategoryID with values like H000021.
I cannot apply join unless data is same.
So I want to split or remove the unnecessary data contained in TransctionId so that I can join both tables.
Kindly help me with the solutions.
Create a computed column with the code only.
Initial scenario:
create table Transactions
(
transactionId varchar(12) primary key,
whatever varchar(100)
)
create table Category
(
transactionId varchar(7) primary key,
name varchar(100)
)
insert into Transactions
select'|H000021|B1|', 'Anything'
insert into Category
select 'H000021', 'A category'
Add computed column:
alter table Transactions add transactionId_code as substring(transactionid, 2, 7) persisted
Join using the new computed column:
select *
from Transactions t
inner join Category c on t.transactionId_code = c.transactionId
Get a straighforward query plan:
You should fix your data so the columns are the same. But sometimes we are stuck with other people's bad design decisions. In particular, the transaction data should contain a column for the category -- even if the category is part of the id.
In any case:
select . . .
from transaction t join
category c
on transactionid like '|' + categoryid + |%';
Or if the category id is always 7 characters:
select . . .
from transaction t join
category c
on categoryid = substring(transactionid, 2, 7)
You can do this using query :
CREATE TABLE #MyTable
(PrimaryKey int PRIMARY KEY,
KeyTransacFull varchar(50)
);
GO
CREATE TABLE #MyTransaction
(PrimaryKey int PRIMARY KEY,
KeyTransac varchar(50)
);
GO
INSERT INTO #MyTable
SELECT 1, '|H000021|B1|'
INSERT INTO #MyTable
SELECT 2, '|H000021|B1|'
INSERT INTO #MyTransaction
SELECT 1, 'H000021'
SELECT * FROM #MyTable
SELECT * FROM #MyTransaction
SELECT *
FROM #MyTable
JOIN #MyTransaction ON KeyTransacFull LIKE '|'+KeyTransac+'|%'
DROP TABLE #MyTable
DROP TABLE #MyTransaction

Replication of the current Identity

I have a table Temp_Identity with a single IDENTITY column.
When we are doing the replication, data from this table is correctly replicated. But its current identity is not replicated.
This means, the current identity of that table in the production database is 10. But in the replication database, it is still 1.
Is there any method to solve this automatically without doing manually?
Table Structure
CREATE TABLE Temp_Identity
(
ID Int IDENTITY(1,1) Primary Key,
Name Varchar(100)
)
When I insert the following values in Production DB ,It is correctly effected inn Replication DB
INSERT INTO Temp_Identity
SELECT 'AA'
UNION ALL
SELECT 'BB'
UNION ALL
SELECT 'CC'
When i Insert the given row from the Replication DB,I got a error.
INSERT INTO Temp_Identity
SELECT 'DD'
It is because,In the Replication DB,the table contains that three rows,When we do the above insertion,the value for the ID column is '1' (Current Identity of that table in Production DB is 3.But in the Replication DB is 1. It should be same as that of Production DB). It is already exists in table.So the Primary Key error raised.
Probably this approach may work in this scenario.
create table tmptbl (ID int identity(1,1) Primary key clustered, name varchar(100))
insert into tmptbl
Select 'A' union all
Select 'B' union all
Select 'C'
Create back up table
create table tmptbl_BCK (ID int identity(1,1) Primary key clustered, name varchar(100))
insert into tmptbl_BCK
select name from tmptbl
delete from tmptbl_BCK --to create the scenario this will remove the previous identity keys and create new keys for new insert.
insert into tmptbl_BCK
select name from tmptbl
select * from tmptbl (in original table)
ID name
1 A
2 B
3 C
select * from tmptbl_BCK
ID name
10 A
11 B
12 C
You can take help of Set Identity Insert option to make sure you have same identity in these tables. First make sure to delete the rows.
delete from tmptbl_BCK
set identity_insert tmptbl_BCK On
insert into tmptbl_BCK (ID, Name) select ID, name from tmptbl
set identity_insert tmptbl_BCK Off
select * from tmptbl_BCK
Output you get:
ID name
1 A
2 B
3 C
Now if you want to have same identity value (in your replication table) as production then you do in this way.
Declare #reseedvalue int = (Select IDENT_CURRENT('tmptbl')) --though it gives you the last inserted value, next time it reseeds it will be 4 in your production table and replication table
--select #reseedvalue
--to reseed based on your production table
DBCC CHECKIDENT ('tmptbl_BCK', RESEED, #reseedvalue)
--test if it creates 4 in your back up table
insert into tmptbl_BCK
select 'D'
select * from tmptbl_BCK

Update records based on inserted IDs and another non source column in SQL

Probably there is already answer for it, but i couldn't find it... So i have 2 tables and data in third one. Lets name them (Source, Target and UpdateTarget).
I need to insert records from Source to Target, then grab autoincremented IDs from Target and update UpdateTarget table with these IDs based on filters from Source table. I've tried to use OUTPUT, but it gives me an error:
The multi-part identifier "s.EmployeeID" could not be bound.
Here is my current SQL query:
CREATE TABLE dbo.target
(
id INT IDENTITY(1,1) PRIMARY KEY,
employee VARCHAR(32)
);
CREATE TABLE dbo.source
(
id INT IDENTITY(1,1) PRIMARY KEY,
employee VARCHAR(32),
EmployeeID int
);
CREATE TABLE dbo.updateTarget
(
id INT IDENTITY(1,1) PRIMARY KEY,
ExternalID int
);
DECLARE #MyTableVar TABLE
(
id INT,
EmployeeID int
);
INSERT dbo.target (employee)
OUTPUT
inserted.id, -- autoincremented ID
s.EmployeeID -- here i got an error
INTO #MyTableVar
SELECT s.employee
FROM dbo.source AS s
UPDATE dbo.updateTarget
SET ExternalID = data.ID
FROM #MyTableVar data
WHERE updateTarget.ID = data.EmployeeID
DROP TABLE source
DROP TABLE target
DROP TABLE updateTarget
I don't have EmployeeID column in target table.
Is there a way to achieve it without making two queries for each record? Or can you point me to existing answer if there are any?
Thanks!
1) INSERT INTO table variable generated id, and EmployeeId for usage in update
2) MERGE instead of INSERT (it allows to get column EmployeeId from SRC)
3) OUTPUT result, action inserted, getting id from TGT and EmployeeId
INSERT INTO #MyTableVar(id, EmployeeId)
SELECT id, EmployeeId
FROM (
MERGE dbo.target TGT
USING dbo.source SRC
ON TGT.employee = SRC.employee
WHEN NOT MATCHED THEN
INSERT (employee)
VALUES (src.employee)
OUTPUT inserted.id, SRC.EmployeeId)
AS out(id, EmployeeId);;
MERGE gives better OUTPUT options

Is it possible to create indexes on a temp table when using SELECT INTO?

I am loading data from a CSV file into a temp staging table and this temp table is being queried a lot. I looked at my execution plan and saw that a lot of the time is spent scanning the temp table.
Is there any way to create index on this table when I SELECT INTO it?
SELECT *
FROM TradeTable.staging.Security s
WHERE (
s.Identifier IS NOT NULL
OR s.ConstituentTicker IS NOT NULL
OR s.CompositeTicker IS NOT NULL
OR s.CUSIP IS NOT NULL
OR s.ISIN IS NOT NULL
OR s.SEDOL IS NOT NULL
OR s.eSignalTicker IS NOT NULL)
The table created by SELECT INTO is always a heap. If you want a PK/Identity column you can either do as you suggest in the comments
CREATE TABLE #T
(
Id INT IDENTITY(1,1) PRIMARY KEY,
/*Other Columns*/
)
INSERT INTO #T
SELECT *
FROM TradeTable.staging.Security
Or avoid the explicit CREATE and need to list all columns out with
SELECT TOP (0) IDENTITY(int,1,1) As Id, *
INTO #T
FROM TradeTable.staging.Security
ALTER TABLE #T ADD PRIMARY KEY(Id)
INSERT INTO #T
SELECT *
FROM TradeTable.staging.Security