How to insert data into a vertically partitioned table in sql server - sql

I have a problem with the partitioning of a table in the SQL Server. I have a table with over 103 columns out of which only 20 are used very frequently and are referenced by a number of tables.
As the table contains thousands of rows I have created a vertical partition and divided the table into multiple tables so as to save the table data in different file groups.
I have also created a view by joining those tables. And now, how do i insert data into different tables without using INSTEAD OF triggers?

You can use stored procedure to encapsulate all your insert logic.
If you have, let's say, 3 tables that share same ID column and each have it additional columns, your stored procedure might look something like this:
CREATE PROCEDURE usp_Insert
(
#Val1 VARCHAR(5)
, #Val2 VARCHAR(5)
, #Val3 VARCHAR(5)
)
AS
BEGIN
DECLARE #id INT;
INSERT INTO Table1 (Col1) VALUES (#Val1);
SELECT #id = SCOPE_IDENTITY();
INSERT INTO Table2 (ID, Col2) VALUES (#id, #Val2);
INSERT INTO Table3 (ID, Col3) VALUES (#id, #Val3);
END
GO
SQLFiddle Working demo and sample tables

Related

Assign values from a table variable to each row of a table?

I have a table (Reference table) that will hold unique values (uniqueidentifer types).
I have two million users and I need to generate a unique value for each one in this Reference table.
As I create them, I would like to capture these unique values and assign them to each user in another table, called a User table.
Below is my attempt: I have created a table variable called #ReferenceIds. How can I take #ReferenceIds and assign each unique value to a separate row in the User table?
create procedure create_reference_ids
#numberOfNewAccounts int
DECLARE #ReferenceIds TABLE (Id uniqueidentifier)
set #numberOfNewAccounts = 2000000
as
begin
while #numberOfNewAccounts > 0
begin
insert into Reference (0,0,#UtcNow,#UtcNow)
OUTPUT Inserted.Id INTO #ReferenceIds
set #numberOfNewAccounts = #numberOfNewAccounts - 1
end
end
exec create_reference_ids
Use a merge statement to insert the exact number of reference values as you have users, and output the new Ids into a table variable which links your new reference ids to your existing user ids. Then carry out an update on your users table.
DECLARE #NewId TABLE (UserId int, ReferenceId int);
-- Using Merge for insert is the only way to get values from columns in the output table which don't exist in the Target table
MERGE INTO dbo.Reference AS Target
USING dbo.[User] AS Source
ON 1 = 0 -- Force an insert regardless
WHEN NOT MATCHED THEN
-- Best practice is to always explicitly name your columns
INSERT (Col1, Col2, Col3, Col4)
VALUES (0, 0, #UtcNow, #UtcNow)
OUTPUT Source.Id, Inserted.Id
INTO #NewId (UserId, ReferenceId);
UPDATE U SET
ReferenceId = I.ReferenceId
FROM dbo.[User] U
INNER JOIN #NewId I on I.UserId = U.Id;

How to insert data from source table (but different columns) into two different tables in SQL Server

I have a staging table titled [Staging]. The data from this table needs to be inserted into two separate tables. Half of the columns go to the first table (we'll call it [Table1]) and the other half go to a second table (we'll call it [Table2])
Both of these tables have a column titled "ChainID". In [Table1] the ChainID is an identity column. In [Table2] it's not.
The ChainID is the one column that links these two tables together for when we need to query this data.
I currently have it set up to where it will do the insert into [Table1] which then generates the new ChainIds. I can use "OUTPUT INSERTED.ChainID" to get the ChainId's that were generated but my problem is tying this back to the original staging table in order to grab the rest of the data for the second table.
DECLARE #Staging TABLE
(
[RowID] [int],
[ChainID] [varchar](50) ,
[LoanNo] [varchar](50) ,
[AssignmentFrom] [varchar](4000),
[AssignmentTo] [varchar](4000),
[CustodianUID] [nvarchar](100) null,
[DocCode] [nvarchar](100) null
)
INSERT
#Staging
SELECT
RowID,
ChainID,
LoanNo,
AssignmentFrom,
AssignmentTo,
CustodianUID,
DocCode
FROM
[MDR_CSV].[dbo].[TblCollateralAssignmentChainImport]
WHERE
UploadID = 1
This is where we do the insert into the first table which generates the new chainIds that will be needed to merge into Table2.
INSERT INTO
Table1
SELECT
LoanNo,
AssignmentFrom,
AssignmentTo,
CustodianUID
FROM
#Assignments AS MDRCA
WHERE
MDRCA.ChainID IS NULL
Now I need to insert the data from the DocCode field into Table2. I can get the list of newly generated ChainIds by doing something such as
OUTPUT INSERTED.ChainID
But that doesn't help being able to tie the newly generated chainId's back to the corresponding data rows from the Staging table in order to do the insert into Table2.
I ended up figuring out a solution. I used a curser to go through each row of data from the staging table one by one. That allowed me to do the insert into the first table (with only the pertinent columns from the staging table) along with doing an OUTPUT.INSTERTED ChainID and stored that newly generated ChainID into a table variable. I then assign that ChainID value to a regular variable by doing
#ChainID = (SELECT TOP 1 * FROM #tableVariable)
I could then use this ChainID to insert into the second table along with the rest of the data from the staging table that pertained to the same row of data (which was possible due to the curser)
Then before the curser loops I drop the table variable and recreate it back at the top of the loop so that the SELECT TOP 1 works correctly each time.
Not sure if it's the best or more efficient way to go about this but at least it worked!
Here's an example showing how I got it to work:
TblCollateralAssignmentChainImport is the Staging Table
temp_tblCollateralAssignment is Table1
temp_CustodianData is Table2
DECLARE #RowID int, #ChainID int;
DECLARE import_cur CURSOR FOR
SELECT RowID
FROM [MDR_CSV].[dbo].[TblCollateralAssignmentChainImport]
WHERE ChainId IS NULL
order by RowID;
OPEN import_cur
FETCH NEXT FROM import_cur
INTO #RowID
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #NewlyCreatedChainId table (nChainId int);
INSERT INTO temp_tblCollateralAssignment
OUTPUT INSERTED.ChainID INTO #NewlyCreatedChainId
SELECT LoanNo, AssignmentFrom, AssignmentTo
FROM TblCollateralAssignmentChainImport
WHERE RowId = #RowID
SET #ChainID = (SELECT TOP 1 nChainId FROM #NewlyCreatedChainId)
INSERT INTO temp_CustodianData (ChainID, LoanNo, CustodianUID, DocCode)
SELECT #ChainID, import.LoanNo, import.CustodianUID, import.DocCode
FROM TblCollateralAssignmentChainImport AS import
WHERE RowId = #RowID
DELETE FROM #NewlyCreatedChainId
FETCH NEXT FROM import_cur
INTO #RowID
END
CLOSE import_cur;
DEALLOCATE import_cur;

Combine results from multiple stored procedures

I have 3 stored procedures (spData1, spData2, spData3) that query regional summary results from two tables (tSites, tInspections) linked by a SiteID key. I cannot combine the queries due to differing join methods and GROUP BY requirements of the required summary information. Each stored procedure takes a #Year (smallint) parameter for the year in which they want the summary information. And to makes things really fun, the procedures don't always return the same number of records, depending on the year.
spData1 returns RegionName, TotalSitesVisited, and TotalViolations
spData2 returns RegionName and TotalSiteVisits
spData3 returns RegionName and TotalBadSites
How do I create a fourth stored procedure to return all of this information in one result:
spData4 returns RegionName, TotalSitesVisited, TotalViolations, TotalSiteVisits, TotalBadSites
Thanks!
At the beginning of your procedure (spData4) create three temp tables that corespond to the output columns of three stored procedures.
Run all 3 sps using INSERT..EXEC and insert data into 3 temp tables.
At the end write a query that JOIN the result of 3 temp tables and return it as SELECT from procedure
Something like this (fix for your correct column types):
CREATE PROCEDURE spData4 (#Year smallint)
AS
BEGIN
CREATE TABLE #temp1 (RegionName NVARCHAR(50), TotalSitesVisited INT, TotalViolations INT)
CREATE TABLE #temp2 (RegionName NVARCHAR(50), TotalSiteVisits INT)
CREATE TABLE #temp3 (RegionName NVARCHAR(50), TotalBadSites INT)
INSERT INTO #temp1 EXEC spData1 #Year
INSERT INTO #temp2 EXEC spData2 #Year
INSERT INTO #temp3 EXEC spData3 #Year
SELECT
COALESCE(t1.RegionName, t2.RegionName, t3.RegionName) RegionName
,TotalSitesVisited,TotalViolations,TotalSiteVisits,TotalBadSites
FROM #temp1 t1
FULL JOIN #temp2 t2 ON t1.RegionName = t2.RegionName
FULL JOIN #temp3 t3 ON t1.RegionName = t3.RegionName OR t2.RegionName = t3.RegionName
END
Alternatively, if you don't need old SPs anymore, you can copy your code from all three SPs here and have it as three separate parts that each fill it's own #temp table. Join at the end the same way.

Get SCOPE_IDENTITY value when inserting bulk records for SQL TableType

I have following table structure, for convenience purpose I am only marking individual columns
Table_A (Id, Name, Desc)
Table_1 (Id this is identity column, Name....)
Table_2 (Id this is identity column, Table_A_Id, Table_1_Id)
The relationship between Table_1 and Table_2 is 1...*
Now I have created a table type for Table_A called TType_Table_A (which only contains Id as column and from my C# app I send multiple records). I have achieved this bulk insert functionality as desired.
What I need is when I insert records into Table_2 from TType_Table_A say with below statements, I would like to capture the Id of Table_2 for each record inserted
declare #count int = (select count(*) from #TType_Table_A); --a variable declared for TType_Table_A
if(#count > 0)
begin
insert into Table_2(Table_A_Id,Table_1_Id)
SELECT #SomeValue, #SomeValueAsParameter FROM #TType_Table_A;
end;
Now say if 2 records are inserted, I would like to capture the Id for each of these 2 records.
Any input/help is appreciated
This is what I know how it can be achieved, but I want to reduce DB calls from my app or user cursor in stored procedure
Insert record in Table_1 and return back the Id Loop.....through records and insert record in Table_2 and return back the Id
OR
Use cursor in stored procedure when inserting/selecting from TableType
I assume this is Sql Server? Then you can make use of the OUTPUT clause, like so:
declare #NewId table (MyNewId INT)
insert into Table_2(Table_A_Id,Table_1_Id)
output INSERTED.MyNewId INTO #TempTable(MyNewID)
SELECT SomeValue, SomeValueAsParameter FROM #TType_Table_A;
SELECT * FROM #NewId

Insert into Table select result set from stored procedure but column count is not same

I need something like that which is of course not working.
insert into Table1
(
Id,
Value
)
select Id, value from
(
exec MySPReturning10Columns
)
I wanted to populate Table1 from result set returned by MySPReturning10Columns. Here the SP is returning 10 columns and the table has just 2 columns.
The following way works as long as table and result set from SP have same number of columns but in my case they are not same.
INSERT INTO TableWith2Columns
EXEC usp_MySPReturning2Columns;
Also, I want to avoid adding "." as linked server just to make openquery and openrowset work anyhow.
Is there a way not to have define table strucutre in temp table (all columns with datatypes and lenght)? Something like CTE.
You could use a temporary table as a go-between:
insert into #TempTable exec MySP
insert into Table1 (id, value) select id, value from #TempTable
You could solve the problem in two steps by doing the insert from the stored procedure into a temporary table, then do the insert selecting just the columns you want from the temporary table.
Information on temporary tables: http://www.sqlteam.com/article/temporary-tables
-- Well, declare a temp table or a table var, depending on the number of rows expected
-- from the SP. This table will be basically the result set of your SP.
DECLARE #spResult AS TABLE
(
ID INT,
VALUE FLOAT,
....
);
-- Get the result set of the SP into the temp table.
INSERT #spResult EXEC STORED_PROC;
-- Now you can query the SP's result set for ID and Value;
INSERT Table1 (ID, VALUE)
SELECT ID, VALUE FROM #spResult;
You dont need to create a temporary table, you can do it with single query by creating temporary view like this
with tempView as EXEC MySPReturning10Columns insert into Table1 select id, value from tempView
The temporary view disappears as soon as the statement finishes execution