Extracting a table field with CSV data - sql-server

I'm looking into ways to extract data from a particular field in a table. The field has CSV data, and I'd like to put them all in a temp table as individual entries. For example,
Create Table #temp (CsvData Varchar(500))
Insert Into #temp Values ('1,2,3,4'), ('3,6,7,9'), ('a,b,c,d'), ('d,f,g,h')
How can I extract the data from this CsvData column into another temp table? Ideally I'd like to get unique values, but at this point I'm willing to clean up the data after I get them all.

Working example:
Create Table #temp (CsvData Varchar(500));
Create Table #temp2 (OneValue Varchar(500));
Insert Into #temp Values
('1,2,3,4'), ('3,6,7,9'), ('a,b,c,d'), ('d,f,g,h');
DECLARE #s VarChar(Max) = '';
SELECT #s = #s + Replace('INSERT INTO #temp2
VALUES('''+CsvData+''')',',','''),(''') FROM #temp;
PRINT #s;
EXEC (#s);
SELECT * FROM #temp2;
DROP TABLE #temp;
DROP TABLE #temp2;

Related

Get more than 1 id to new inserted row

I have this data.
I want to duplicate data like a picture above with stored procedure.
First thing I do is copying two rows in the first table. How can I get 2 (two) 'iId' in the first table to create 2 (two) rows in the second table and put those 'iId' into 'iId_JTS-Rule_RulePricingGroup' like the picture above?
I think you can use OUTPUT clause with INSERT
CREATE TABLE #Table1(
ID int IDENTITY PRIMARY KEY,
Title varchar(10)
)
CREATE TABLE #Table2(
ID int,
Title varchar(10)
)
DECLARE #NewIDs TABLE(ID int)
INSERT #Table1(Title)
OUTPUT inserted.ID INTO #NewIDs(ID) -- save new IDs
VALUES ('A'),('B'),('C')
INSERT #Table2(ID,Title)
SELECT ID,Title
FROM #Table1
WHERE ID IN(SELECT ID FROM #NewIDs) -- use new IDs
DROP TABLE #Table1
DROP TABLE #Table2

How can I split the contents of my table into two tables with an index?

I have a SQL Server table with the schema
varchar type,
varchar id,
int date,
varchar(MAX) data
And I want to split the data column into its own table and give it a unique index that I would put in my existing table (altered to accept an int instead of varchar(max) for data)
How can I select all of the rows and insert the data column into one table, then take the newly created auto_incremented id and insert the rest of the columns into another table with the auto_incremented id as the new 4th column?
Move the table to new temp table with Identity column. from that table, first create your new data table, then again create your second table.
declare #OriginalTable (type varchar, id Varcher,date int, data varchar(MAX))
declare #TempTable (Ident int identity(1,1), type varchar, id archer,date int, data varchar(MAX))
insert into #TempTable (type, id, date, data) select * from # OriginalTable
-- Create the Split tables
select ident, type, id, date into #Table1 From #TempTable
select ident, data into #Table2 From #TempTable

Truncate existing table within a stored procedure then insert fresh data

I have a stored procedure that returns a result set. After that I insert this result set into created real table. And then I am using that real table create SSRS reports.
So, something like this:
CREATE PROCEDURE Test
AS
DECLARE #TempTable TABLE(..)
INSERT INTO #TempTable
SELECT...
FROM ...
WHERE ...
SELECT * FROM #TempTable
--============================
INSERT INTO RealTable EXEC [dbo].[Test]
How can I modify this stored procedure so every time it executed it will truncate table with existing data and then insert a fresh one?
So I need something like that:
create procedure Test
as
TRUNCATE RealTable
DECLARE #TempTable TABLE(..)
INSERT INTO #TempTable
SELECT...
FROM...
WHERE...
SELECT * FROM #TempTable INTO RealTable
Or should I just create agent job that would run command something like:
Truncate Table RealTable
INSERT INTO RealTable EXEC [dbo].[Test]
Am I on a right way in terms of logic?
Dont TRUNCATE. Use a MERGE Statement.
CREATE PROCEDURE Test
AS
MERGE RealTable TRGT
USING SourceTable SRCE
ON SRCE.[Column] = TRGT.Column --use columns that can be joined together
WHEN MATCHED THEN UPDATE
SET TRGT.Column1 = SRCE.Column1,
TRGT.Column2 = SRCE.Column2
....................
WHEN NOT MATCHED BY TARGET THEN INSERT
VALUES
(
SRCE.Column1,
SRCE.Column2,
.....................
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
What's the purpose of the truncate if you are inserting the same data?
What should happen if you have more then 1 concurrent user?
another thing you can do:
1.
insert into TargetTable
select * from SourceTable
2.
rebuild indexes on TargetTable
3.
exec sp_rename SourceTable, SourceTable_Old
exec sp_rename TargetTable, SourceTable
drop table SourceTable_Old
this is an old way of entire table data refresh without much impact, when table variable was not an option.
this is what you probably need as you are directly inserting from #TempTable to RealTable.
create procedure Test
as
BEGIN
TRUNCATE TABLE RealTable
INSERT INTO RealTable
SELECT...
FROM someothertable
WHERE...
END

Create Unique ID in Stored Procedure to Match Legacy Data

I'm creating CRUD procedures that duplicate a legacy program that generates a unique ID based on a 'Next ID' field in a separate table. Rather than duplicate the use of a separate table I have written a stored procedure that reads the number of rows in the table.
CREATE PROCEDURE [TLA_CreateItem]
#SiteReference varchar(50)
,#ItemID varchar(4)
,#NewUniqueID varchar(68) OUTPUT
AS
BEGIN
DECLARE #Rows varchar(12)
SET #Rows = (CONVERT(varchar(12), (SELECT Count(UniqueID) FROM [TLA_Items]) + 1))
SET #NewUniqueID = #ItemID + #SiteReference + #Rows
INSERT INTO [TLA_Items] ([ItemID], [UniqueID])
VALUES (#ItemID, #NewUniqueID)
SELECT #NewUniqueID
END
I've simplified the code above but what's not shown is that the TLA_Items table also has an IDENTITY column and that it needs to work with SQL Server 2008.
The UniqueID field has to match the pattern of the legacy program: ItemID + SiteReference + (integer representing number of previous records)
However when testing this I've found a flaw in my logic. If rows are deleted then it's possible to create a unique Id which matches an existing row. This doesn't happen in the legacy system as rows are rarely deleted and the separate table stores the next number in the sequence.
Other than store the next ID value in a separate table, is there a better technique, to create a unique ID that matches the legacy pattern?
You could have your procedure store only the prefix (#ItemID + #SiteReference) into UniqueID and use a FOR INSERT trigger to append the IDENTITY value as the rows component immediately after the row is inserted, something like this:
CREATE TRIGGER TLA_Items_Adjust
ON dbo.TLA_Items
FOR INSERT
AS
BEGIN
UPDATE t
SET t.UniqueID = i.UniqueID + CAST(t.IdentityColumn AS varchar(10))
FROM dbo.TLA_Items AS t
INNER JOIN inserted AS i
ON t.IdentityColumn = i.IdentityColumn
;
END
To read and return the newly generated UniqueID value as the OUTPUT parameter as well as a row, you could use a table variable and the OUTPUT clause in the INSERT statement, like this:
CREATE PROCEDURE [TLA_CreateItem]
#SiteReference varchar(50)
,#ItemID varchar(4)
,#NewUniqueID varchar(68) OUTPUT
AS
BEGIN
DECLARE #GeneratedUniqueID TABLE (UniqueID varchar(68));
INSERT INTO dbo.[TLA_Items] ([ItemID], [UniqueID])
OUTPUT inserted.UniqueID INTO #GeneratedUniqueID (UniqueID)
VALUES (#ItemID, #ItemID + #SiteReference);
SELECT #NewUniqueID = UniqueID FROM #GeneratedUniqueID;
SELECT #NewUniqueID;
END
Although instead of using OUTPUT you could probably just read the value from the row matching the SCOPE_IDENTITY() result:
CREATE PROCEDURE [TLA_CreateItem]
#SiteReference varchar(50)
,#ItemID varchar(4)
,#NewUniqueID varchar(68) OUTPUT
AS
BEGIN
INSERT INTO dbo.[TLA_Items] ([ItemID], [UniqueID])
VALUES (#ItemID, #ItemID + #SiteReference);
SELECT #NewUniqueID = UniqueID
FROM dbo.TLA_Items
WHERE IdentityColumn = SCOPE_IDENTITY();
SELECT #NewUniqueID;
END
Here is another option, but please bear in mind that it would affect existing UniqueID values.
If you can afford a slight change to the table schema, you could add a column called something like UniqueIDPrefix:
ALTER TABLE dbo.TLA_Items
ADD UniqueIDPrefix varchar(56) NOT NULL;
and redefine the UniqueID column to be a computed column:
ALTER TABLE dbo.TLA_Items
DROP COLUMN UniqueID;
GO
ALTER TABLE dbo.TLA_Items
ADD UniqueID AS UniqueIDPrefix + CAST(IdentiyColumn AS varchar(12));
In your stored procedure, you would then need to populate UniqueIDPrefix instead of UniqueID (with just the result of #ItemID + #SiteReference)
INSERT INTO dbo.[TLA_Items] ([ItemID], [UniqueIDPrefix])
VALUES (#ItemID, #ItemID + #SiteReference);
and read the value of UniqueID using either OUTPUT or SCOPE_IDENTITY(), as in my other answer.
It sounds like you are on SQL 2008, but if you were on 2012, you could use a sequence to store an incrementing value.
How about never delete? You could add a flag to the table for logical deletes.

Can I insert into temp table from SP without declaring table?

Here is my code:
alter procedure test1 as
select DeptID,DeptName from Department
go
alter procedure test2 as
--Create Table #tab (DeptID INT, DeptName VARCHAR(255))
INSERT INTO #tab
exec test1
select * from #tab
drop table #tab
go
exec test2
I am getting an error like "Invalid object name #tab"
If I add at the begining Create Table #tab (DeptID INT, DeptName VARCHAR(255)) then I do not get any error.
What is wrong in my code? Can I populate a temp table from the results of a stored procedure without declaring the temp table and its column definitions?
When loading a temp table from a stored procedure, then you have to CREATE the table first.
There is no straightforward equivalent of
SELECT * INTO #temptable FROM AnotherTable
The non-straightforward version (read all about the bad stuff on "How to Share Data Between Stored Procedures". And simpler) would be
SELECT * INTO #temptable FROM OPENQUERY(Loopback, 'exec test1')
It's because the Local Temporary table #tab which you are expecting does not existing in the session.
So the table creation should not be commented line.
Create Table #tab (DeptID INT, DeptName VARCHAR(255))
Moreover, if you want to do without creating the table then it should be like below
Alter procedure test2
As
Set NoCount ON
IF OBJECT_ID('tempdb..#tab') IS NOT NULL
Begin
Drop table #temp
End
SELECT DeptID, DeptName INTO #tab from Department
Select * from #tab
Drop table #tab
Go

Resources