How to INSERT DATA from table to multiple tables with conditions - sql

I need to insert data from source table to different tables by repsecting number of rows provided in a parameter table and without duplicates.
The same ID's in the parameter table should be inserted in the destination tables for each range of rows.
For example :
FOR ID=1 insert first 200 rows in table_A then insert counting 300 lines starting from line 201 in source table .
ID
FILENAME
TOTAL_ROWS
NUMBER_OF_ROWS_TO_INSERT
DESTINATION_TABLE
1
FILENAME_X
500
200
TABLE_A
2
FILENAME_X
500
300
TABLE_B
3
FILENAME_Y
400
100
TABLE_C
4
FILENAME_Y
400
300
TABLE_D
Source table
s_id
PHONE
NAME
78
Cell 1
Cell 2
88
Cell 3
Cell 4
Destination tables
TABLE A, B, C AND D (with same columns)
ID
PHONE
NAME
1
XXXX
XXXX
2
XXXX
XXXX
3
XXXX
XXXX
4
XXXX
XXXX
SELECT ROW_NUMBER() OVER(
ORDER BY FILENAME) AS RowNum, ID,FILENAME,TOTAL_ROWS,NUMBER_OF_ROWS_TO_INSERT,DESTINATION_TABLE
FROM [dbo].[parameter_table] ORDER BY FILENAME
OPEN cursor_files
FETCH NEXT FROM cursor_files INTO #RowNum,#ID,#FILENAME,#TOTAL_ROWS,NUMBER_OF_ROWS_TO_INSERT,#NUMBER_OF_ROWS_TO_INSERT,#DESTINATION_TABLE
WHILE ##FETCH_STATUS=0
BEGIN
IF #NUMBER_OF_ROWS_TO_INSERT > 0
do actions
END
FETCH NEXT FROM cursor_files INTO #RowNum,#ID,#FILENAME,#TOTAL_ROWS,NUMBER_OF_ROWS_TO_INSERT,#NUMBER_OF_ROWS_TO_INSERT,#DESTINATION_TABLE
END
CLOSE cursor_files
DEALLOCATE cursor_files
END

Using dynamic query:
declare #strqry as nvarchar(max) = ''
;with cte (id,destination_table, end_row) as (
select id
,destination_table
,SUM (NUMBER_OF_ROWS_TO_INSERT) OVER (ORDER BY Id) as end_row
from ParameterTable )
select #strqry = #strqry + 'insert into ' + destination_table + '(ID,Phone,Name)
select ' + str(ID) + ', phone, name
from SourceTable
where s_ID>' + str(isnull(Lag(end_row) OVER(ORDER BY id),0)) +' and s_ID<=' + str(end_row) +';'
from cte
exec sp_executesql #strqry
TEST
http://sqlfiddle.com/#!18/0cea4c/1

Related

How to get TWO Previous record in MySQL using CURSOR

On my table, I have records that contain ','.
Id Name
1 Here is the result
2 of your examination.
3 ,
4 New Opening for the position of
5 PT Teacher, Science Lab.
6 ,
So in cursor If I found ',' then I want to merge the 2 rows value into the first one.
DECLARE #ID int
DECLARE #Name nvarchar(500)
DECLARE MergeCursor CURSOR FOR
select ID,NAME from TEST_TABLE
OPEN MergeCursor
FETCH NEXT FROM NarrationCursor into #ID,#NAME
WHILE (##FETCH_STATUS=0)
BEGIN
if(#Name = ',')
select * from TEST_TABLE where ID = (select max(ID) from TEST_TABLE where ID < #ID)
FETCH NEXT FROM NarrationCursor into #ID,#NAME
END
CLOSE MergeCursor
DEALLOCATE MergeCursor
IN cursor how can I get the PREVIOUS TWO-ROW And UPDATE the value in 1st row and DELETE THE 2nd and THIRD ROW. AS WELL AS UPDATE THE ID
In the End, I want to output
Id Name
1 Here is the result of your examination.
2 New Opening for the position of PT Teacher, Science Lab.
WITH
grouped AS
(
SELECT
SUM(CASE WHEN name=',' THEN 1 ELSE 0 END)
OVER (ORDER BY id)
AS group_id,
id,
name
FROM
TEST_TABLE
)
SELECT
group_id + 1 AS id,
STRING_AGG(name, ' ') WITHIN GROUP (ORDER BY id) AS name
FROM
grouped
WHERE
name <> ','
GROUP BY
group_id
ORDER BY
group_id

How to get Output parameter from a column in table for a stored procedure

I've stored procedure like this:
create procedure sp_testsp
(
#vc_order_by varchar(100),
#int_start_index INT,
#int_grid_size INT,
#count bigint output
)
as
begin
select * from
(select ROW_NUMBER() over
(order by
case #vc_order_by = '' then tab1.int_id end desc) AS row,
*,
COUNT(tab1.int_id) OVER() as totalRowCount
from
(select * from tbl_test) tab1) tab2
where row BETWEEN CONVERT(VARCHAR, #int_start_index) and CONVERT(VARCHAR,(#int_start_index-1) + #int_grid_size);
set #count = 0;
end
We can execute the above stored procedure by:
DECLARE #size bigint;
EXEC sp_testsp '', 1,5, #size output;
SELECT #size;
The written sp provides data based on pagination and we can retrieve 100 or any number of records by passing a number in #int_grid_size .
The table output looks like following:
row int_id vc_name totalRowCount
1 5 a 107
2 6 ab 107
3 7 abc 107
4 8 abcd 107
5 10 abcc 107
The last column gives the total records count of the table or total record if we use where condition.
I want to OUTPUT any one column value of the totalRowCount in '#count' in the stored procedure.
I cannot use ##ROWCOUNT as it only sends the count of records the sp is outputting i.e in this case 5 but actual records are 107.
Just wondering if there is any way. Any help is apperciated. Thanks.
Edit:
I tried something like this, and it works:
create procedure sp_testsp
#param1 nvarchar(800),
#count bigint output
as
begin
select * from tbl_test tt where tt.col1 = #param1;
set #count = select Count(*) from tbl_test tt where tt.col1 = #param1;
end
The issue with this is I've to call the query once and then call the query again for #count. This is working but taking lot of time for big queries.
You can do that by temp table
select * into #temp from
(select ROW_NUMBER() over
(order by
case #vc_order_by = '' then tab1.int_id end desc) AS row,
*,
COUNT(tab1.int_id) OVER() as totalRowCount
from
(select * from tbl_test) tab1) tab2
where row BETWEEN CONVERT(VARCHAR, #int_start_index) and CONVERT(VARCHAR,(#int_start_index-1) + #int_grid_size);
select top 1 #count=totalRowCount from #temp
select * from #temp --you can exclude totalRowCount

SQL Server query performance: Nested cursors

I have a stored procedure which is selecting some 1-n relations and related data to the referenced column as XML data.
The purpose is to return a record and it's 1-n relations as ONE record with extra data columns, this is done using adding these related data as XML.
Reference table: (TABLE A)
ID NAME VALUE
---------------------
1 Sepehr 1000
2 Sarah 1001
Related table: (TABLE B)
ID Value FK_Value ORDER TITLE
-------------------------------------
1 A 1000 1 t1
2 B 1000 2 t2
3 C 1000 3 t3
I want to get this output:
ID NAME FK_Value Attribs
-----------------------------------------------------
1 Sepehr 1000 <XML><ID>1</ID><ID>2</ID><ID>3</ID></XML>
2 Sarah 1001 null
Actually I was hoping to create a view to do this, but I couldn't and someone told me its not possible using views.
Finally this is the stored procedure I have written - is this a correct approach or are there any other ways?
DECLARE #T1 table (A_ID int,Attribs XML)
DECLARE db_cursorLegendRowsValues CURSOR FOR
SELECT ID, VALUE
FROM A
OPEN db_cursorLegendRowsValues
FETCH NEXT FROM db_cursorLegendRowsValues INTO #loop_ID, #loop_VALUE
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE db_cursorInternal CURSOR FOR
SELECT TITLE, ORDER
FROM B
WHERE FK_Value = #loop_VALUE
OPEN db_cursorInternal
FETCH NEXT FROM db_cursorInternal INTO #tmpTitle, #ORDER
WHILE ##FETCH_STATUS = 0
BEGIN
SET #querySelect = #querySelect + ', MAX(CASE WHEN order = ' + cast(#ORDER as nvarchar(max)) + ' THEN value END) AS [' +REPLACE (#tmpTitle,' ','_') + '] '
FETCH NEXT FROM db_cursorInternal INTO #tmpTitle, #ORDER
END
CLOSE db_cursorInternal
DEALLOCATE db_cursorInternal
SET #query =
' SELECT ' + cast(#loop_ID as nvarchar(max)) +',(
SELECT A.Value,
'
SET #query = #query + STUFF(#querySelect,1,1,'') + ' FROM A
WHERE [A.Value] = ' + cast(#loop_VALUE as nvarchar(max)) + '
FOR XML RAW (''Item''), root (''Items'') , ELEMENTS XSINIL )'
SET #querySelect = ''
--PRINT(#query)
INSERT into #T1 execute (#query )
FETCH NEXT FROM db_cursorLegendRowsValues INTO #loop_ID, #loop_VALUE
END
CLOSE db_cursorLegendRowsValues
DEALLOCATE db_cursorLegendRowsValues
SELECT * FROM #T1
The whole lot can be condensed to a few lines, no cursors needed at all. This wil be useable in a VIEW:
DECLARE #tblA TABLE(ID INT IDENTITY,NAME VARCHAR(100),VALUE INT);
INSERT INTO #tblA VALUES
('Sepehr',1000)
,('Sarah',1001);
DECLARE #tblB TABLE(ID INT IDENTITY,Value VARCHAR(100),FK_Value INT,[ORDER] INT,TITLE VARCHAR(100));
INSERT INTO #tblB VALUES
('A',1000,1,'t1')
,('B',1000,2,'t2')
,('C',1000,3,'t3');
SELECT a.*
,(SELECT ID FROM #tblB AS b WHERE b.FK_Value=a.VALUE FOR XML PATH(''),ROOT('XML'),TYPE) AS Attribs
FROM #tblA AS a
The result
ID NAME VALUE Attribs
1 Sepehr 1000 <XML><ID>1</ID><ID>2</ID><ID>3</ID></XML>
2 Sarah 1001 NULL
It is possible to do this with just one query - you can use a subquery with your select as follows:
select id
, name
, value as fk_value
, (select id from #table_b b
where a.value = b.fk_value
for xml path (''), root ('xml'))
from #table_a a

SQL Select Column From Table Based on Another Select Statement

I have a table containing column names from another table. I want to run an update statement to update some values from that table, based off of the other.
EX:
TableA
ID|Column1|Column2
1 | 1.3 | 2.3
2 | 0 | 7
3 | 2.5 | 12.1
TableB
ID|ColumnName|MaxValue
1 | Column1 | NULL
2 | Column2 | NULL
Something along the lines of this:
So in this case, I would want to update MaxValue in TableB to be the max value from TableA where ColumnName is a colum in TableA.
Is this possible?
You can do it with a cursor and some dynamic sql. This isn't the best thing to do but if you needed a quick and dirty solution here you go:
DECLARE #colName VARCHAR(50), #str VARCHAR(2000), #id int
DECLARE c CURSOR FOR
SELECT id, columnName
FROM tableB
OPEN c
FETCH NEXT FROM c INTO #id, #columnName
WHILE ##fetch_status = 0
BEGIN
SET #str = 'update tableB set MaxValue = ( select max(' + #colName + ') from
tableA ) where id = ' + CONVERT(VARCHAR, #id)
EXEC ( #str )
FETCH NEXT FROM c INTO #id, #columnName
END
CLOSE c
DEALLOCATE c
If you do not want to use dynamic SQL, you could always do something like this
Update TableB
Set MaxValue = MaxValues.MaxValue
From TableB
Join
(
Select MaxValue = Max(Column1)
,ColumnName = 'Column1'
From TableA
Union All
Select MaxValue = Max(Column2)
,ColumnName = 'Column2'
From TableA
-- Union All ... and so on for all columns
) MaxValues
On TableB.ColumnName = MaxValues.ColumnName
Remember, if the TableA DDL changes, you must update this DML.

get specific rows of table given a rule SQL Server 2008

I have a table like:
ID NAME VAL
----------------------
1 a1*a1 90052
2 a1*a2 236
3 a1*a3 56
4 a1*a4 6072
5 a1*a5 1004
6 a2*a2 4576
7 a2*a3 724
8 a2*a4 230
9 a2*a5 679
10 a3*a3 5
11 a3*a4 644
12 a3*a5 23423
13 a4*a4 42354
14 a4*a5 10199
15 a5*a5 10279
Given a number given S = 5, I want to query
the rows wth id: 1,6,10,13,15
they are a1*a1,a2*a2,a3*a3,a4*a4 and a5*a5
I would like something like:
INSERT #NEW_TABLE (ID,NAME,Value) (
SELECT ordinal, NAME, VAL FROM myTable where id = 1,6,10,13,15)
to get
ID NAME VAL
----------------------
1 a1*a1 90052
2 a2*a2 4576
3 a3*a3 5
4 a4*a4 42354
5 a5*a5 10279
Is there a way to do this for any given S, Maybe wth dynamic sql?
I was getting the formula and I got this:
S=5
ID formula
1 1
6 1+S
10 1+S+ (S-1)
13 1+S+ (S-1) + (S-2)
15 1+S+ (S-1) + (S-2) + (S-3)
Is there a way to do this inside a case or a while loop?
This worked in testing.
You can just inner join on #Tab to limit your results. You probably also want to add some traps for values below 3, which I haven't done.
The basic process is
Declare your #s value
Insert the first two rows since they will always be the same
In a loop, insert one row at a time with an incrementing difference
Loop exits once it has run #s-2 times
Try:
DECLARE #Tab Table (id INT)
DECLARE #S int = 5,
#ct int
DECLARE #cur int = (1 + #S)
INSERT INTO #Tab SELECT 1
INSERT INTO #Tab SELECT (1 + #S)
SET #ct = 1
WHILE #ct <= #S - 2
BEGIN
SET #cur = #cur + (#S - #ct)
INSERT INTO #Tab SELECT #cur
SET #ct = #ct + 1
END
SELECT * FROM #Tab
ORDER BY id
To use this in your query, you can do either:
SELECT ordinal, NAME, VAL
FROM myTable
WHERE id IN (SELECT id FROM #Tab)
-- OR
SELECT ordinal, NAME, VAL
FROM myTable t
INNER JOIN #tab t2
ON t2.id = t.id