Bulk insert with SQL Server where one column has many values and all other columns take on preset values - sql-server

I have a table (Table1) that has 4 columns (ID1, ID2, Percent, Time, Expired). I want to insert a bunch of new rows in that table where ID1 is taken from another SQL query I have and all the other columns are set to some specified values.
So I have my query:
SELECT someID FROM other_tables WITH other_conditions
And essentially what I want to do is
FOR v in <above query>
Insert New row into Table1 (v, some second id, some percent, some time, some expired value)
EDIT I'm not opposed to not doing this in a loop, just don't know what the best way to insert the data is

You can use a cursor and fetch I think for what you are trying to accomplish. Here is a shell for you...
WITH CURSOR
DECLARE c CURSOR FOR
SELECT DISTINCT colName FROM Table1 JOIN Table2 ON <stuff> WHERE <other_stuff>
DECLARE #ID VARCHAR(4) --or what ever is needed
OPEN c
FETCH NEXT FROM c INTO #ID
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO Table1 (ID, ID2, Percent, Time, Expired)
VALUES (#ID, some second id, some percent, some time, some expired value)
WHERE ID = #ID
FETCH NEXT FROM c INTO #ID
END
CLOSE c
DEALLOCATE c
WITH CROSS APPLY (DUMMY DATA)
if object_id('tempdb..#ids') is not null drop table #ids
if object_id('tempdb..#idDetails') is not null drop table #idDetails
create table #ids (id int)
insert into #ids (id) values
(1),(2),(3)
select i.*, d.*
into #idDetails
from #ids i cross apply (select 2 as id2 ,2.0 as per,'1/1/2016' as dt,'x' as x) d
select * from #idDetails
WITH CROSS APPLY (EXAMPLE WITH YOUR TABLES)
select i.someID, d.*
into #idDetails
from other_tables i
cross apply (select 'some second id' as id2 ,'some percent' as [Percent],'1/1/2016 14:55:22' as [SomeTime] as dt,'SomeExpiredVal' as [ExpiredVal]) d
select * from #idDetails

Maybe I am missing something, but you need a table valued function which returns the desired row for each row in Table1
create function fn_get_new_recs(id int)
RETURNS #results TABLE (Id INT,<other columns you need>)
AS
BEGIN
--Query here to return new records for a single id
END
then use CROSS APPLY
INSERT INTO Table1(Id,Col1,Col2,Col3)
SELECT ST.Id,ST.Col1,ST.Col2,ST.Col3
FROM Table1 T
cross apply fn_get_new_recs(T.Id) ST

Related

How to insert column from another table when inserting it from userdefined datatable?

CREATE PROC [dbo].[usp_InsertBulkShipmentData]
(
#RetVal VARCHAR(1000) OUTPUT,
#ship dbo.ShipmentData READONLY
)
AS
DECLARE #ShipmentID BIGINT
Declare #Output table (id int)
BEGIN
INSERT INTO
dbo.Shipment (ShipmentType,scaccode,ShipmentControl,countryLoading,PortLoading,ShipperName,ShipperAddressOne,ShipperCity,ShipperCountry,ShipperProvince,
ShipperZip,ShipperPhone,ShipperEmail,ConsigneeName,ConsigneeAddressOne,ConsigneeCity,ConsigneeCountry,ConsigneeState,ConsigneeZip,
ConsigneePhone,ConsigneeEmail,ResponseCode,astrayExportDate,bondType,bondDestPort,bondOnwardscac,bondCarrierIRS,
bondNumber,bondTransferIRS,bondForeignPort,bondDepartureDate,MexiPediNumber)
OUTPUT Inserted.id into #Output
SELECT sh.DDcode,s.SCACCode,s.ShipmentControl,s.CountryLoading,s.ProvinceLoading,s.ShipperName,s.ShipperAddress,s.ShipperCity,s.ShipperCountry,s.ShipperProvince,
s.ShipperZip,s.ShipperPhone,s.ShipperEmail,s.ConsigneeName,s.ConsigneeAddressOne,s.ConsigneeCity,s.ConsigneeCountry,s.ConsigneeState,s.ConsigneeZip,
s.ConsigneePhone,s.ConsigneeEmail,s.CustomControl,s.DateShipmentLeft,s.InbondEntryType,s.InbondDestination,s.OnwardCarrier,s.BondCarrier,
s.Inbond,s.bondTransfer,s.ForeignPortDestination,s.EstimatedDeparture,s.MexiPediNumber
FROM #ship s INNER JOIN ShipmentTypeDropDown sh on sh.DisplayName=s.ShipmentType
select id from #Output
SET #RetVal = 'true|Record Inserted Successfully|'
END
BEGIN
SELECT #ShipmentID=id;
INSERT INTO dbo.Ship_commodity([Description],Quantity,manifestUnitCode,
[weight],weightUnitCode,countryCode,customsShipmentValue,commodityCode,MarksNumbers)
SELECT sp.CommoditiesDescription,sp.Quantity,qu.DDCode,sp.
[Weight],wu.DDCode,sp.CountryOrigin,sp.Value,sp.HarmonizedCode,sp.MarksNumbers
FROM #ship sp INNER JOIN WeightUnitDropDown wu on wu.DisplayName=sp.WeightUnitCode
INNER JOIN QuantityUnitDropDown qu on qu.DisplayName=sp.QuantityUnit
END
id is autogenerated in Shipment table. I wan to insert this id into Ship_commodity where ShipmentID=id.
I am inserting the records from user defined datatable, for every record , id is generated in Shipment table. When inserting into
Ship_commodity table i want to insert the Shipment id for every record , where ShipmentID=id.
How should i achieve this? please suggest.
In your first insert, you need to get the primary key of #ship to be able to join the output table to it (make sure to add extra columns to #output):
OUTPUT inserted.id, inserted.scaccode, inserted.ShipmentControl into #Output
Then you can join #output to #ship (i'm assuming Ship_commodity has a column fkShipmentId):
INSERT INTO dbo.Ship_commodity
(fkShipmentId, [Description], Quantity, manifestUnitCode, [weight], weightUnitCode,
countryCode, customsShipmentValue, commodityCode, MarksNumbers)
SELECT
i.id,
sp.CommoditiesDescription,
sp.Quantity,
qu.DDCode,
sp.[Weight],
wu.DDCode,
sp.CountryOrigin,
sp.Value,
sp.HarmonizedCode,
sp.MarksNumbers
FROM #ship sp
INNER JOIN WeightUnitDropDown wu on wu.DisplayName=sp.WeightUnitCode
INNER JOIN QuantityUnitDropDown qu on qu.DisplayName=sp.QuantityUnit
INNER JOIN #output i ON i.scaccode = sp.scaccode AND i.ShipmentControl = sp.ShipmentControl;

PATINDEX all values of a column

I'm making a query that will delete all rows from table1 that has its column table1.id = table2.id
table1.id column is in nvarchar(max) with an xml format like this:
<customer><name>Paulo</name><gender>Male</gender><id>12345</id></customer>
EDIT:
The id column is just a part of a huge XML so the ending tag may not match the starting tag.
I've tried using name.nodes but it only applies to xml columns and changing the column datatype is not a choice, So far this is the my code using PATINDEX
DELETE t1
FROM table1 t1
WHERE PATINDEX('%12345%',id) != 0
But what I need is to search for all values from table2.id which contains like this:
12345
67890
10000
20000
30000
Any approach would be nice like sp_executesql and/or while loop, or is there a better approach than using patindex? thanks!
Select *
--Delete A
From Table1 A
Join Table2 B on CharIndex('id>'+SomeField+'<',ID)>0
I don't know the name of the field in Table2. I am also assuming it is a varchar. If not, cast(SomeField as varchar(25))
EDIT - This is what I tested. It should work
Declare #Table1 table (id varchar(max))
Insert Into #Table1 values
('<customer><name>Paulo</name><gender>Male</gender><id>12345</id></customer>'),
('<customer><name>Jane</name><gender>Femail</gender><id>7895</id></customer>')
Declare #Table2 table (SomeField varchar(25))
Insert into #Table2 values
('12345'),
('67890'),
('10000'),
('20000'),
('30000')
Select *
--Delete A
From #Table1 A
Join #Table2 B on CharIndex('id>'+SomeField+'<',ID)>0
;with cteBase as (
Select *,XMLData=cast(id as xml) From Table1
)
Select *
From cteBase
Where XMLData.value('(customer/id)[1]','int') in (12345,67890,10000,20000,30000)
If you are satisfied with the results, change the final Select * to Delete

T-SQL: Two Level Aggregation in Same Query

I have a query that joins a master and a detail table. Master table records are duplicated in results as expected. I get aggregation on detail table an it works fine. But I also need another aggregation on master table at the same time. But as master table is duplicated, aggregation results are duplicated too.
I want to demonstrate this situation as below;
If Object_Id('tempdb..#data') Is Not Null Drop Table #data
Create Table #data (Id int, GroupId int, Value int)
If Object_Id('tempdb..#groups') Is Not Null Drop Table #groups
Create Table #groups (Id int, Value int)
/* insert groups */
Insert #groups (Id, Value)
Values (1,100), (2,200), (3, 200)
/* insert data */
Insert #data (Id, GroupId, Value)
Values (1,1,10),
(2,1,20),
(3,2,50),
(4,2,60),
(5,2,70),
(6,3,90)
My select query is
Select Sum(data.Value) As Data_Value,
Sum(groups.Value) As Group_Value
From #data data
Inner Join #groups groups On groups.Id = data.GroupId
The result is;
Data_Value Group_Value
300 1000
Expected result is;
Data_Value Group_Value
300 500
Please note that, derived table or sub-query is not an option. Also Sum(Distinct groups.Value) is not suitable for my case.
If I am not wrong, you just want to sum value column of both table and show it in a single row. in that case you don't need to join those just select the sum as a column like :
SELECT (SELECT SUM(VALUE) AS Data_Value FROM #DATA),
(SELECT SUM(VALUE) AS Group_Value FROM #groups)
SELECT
(
Select Sum(d.Value) From #data d
WHERE EXISTS (SELECT 1 FROM #groups WHERE Id = d.GroupId )
) AS Data_Value
,(
SELECT Sum( g.Value) FROM #groups g
WHERE EXISTS (SELECT 1 FROM #data WHERE GroupId = g.Id)
) AS Group_Value
I'm not sure what you are looking for. But it seems like you want the value from one group and the collected value that represents a group in the data table.
In that case I would suggest something like this.
select Sum(t.Data_Value) as Data_Value, Sum(t.Group_Value) as Group_Value
from
(select Sum(data.Value) As Data_Value, groups.Value As Group_Value
from data
inner join groups on groups.Id = data.GroupId
group by groups.Id, groups.Value)
as t
The edit should do the trick for you.

How to use CTE instead of Cursor

I want to use Common Table Expressions (CTE) instead of Cursor in SQL Server 2012. Your assistance is highly appreciated.
This is my situation:
DECLARE
#tp_ID INTEGER
truncate table T_Rep_Exit_Checklist_Table
DECLARE cursorName CURSOR -- Declare cursor
LOCAL SCROLL STATIC
FOR
SELECT
tp_ID
from V_Rep_Exit_Checklist
OPEN cursorName -- open the cursor
FETCH NEXT FROM cursorName INTO #tp_ID
WHILE ##FETCH_STATUS = 0
BEGIN
insert into T_Rep_Exit_Checklist_Table
SELECT
#tp_ID-- AS tp_ID
,Item_Status_Code
,Item_Status_Desc
,Item_Code
,Item_Desc
,Item_Cat_Code
,Item_Cat_Desc
,Item_Cleared_By_No
,Item_Cleared_By_Name
V_Rep_Exit_Checklist c
FETCH NEXT FROM cursorName
INTO #tp_ID
END
CLOSE cursorName -- close the cursor
DEALLOCATE cursorName -- Deallocate the cursor
Something about your query doesn't seem to make sense. It seems like your INSERT statement with the SELECT is missing a where clause and therefore if you source view have 5 records for instance, you insert 25 records because you take the id of the first record during the first iteration with the cursor, and insert all records with that id, then repeat for each row of the view.
Assuming the above logic is intended, then you should just need a CROSS JOIN:
INSERT T_Rep_Exit_Checklist_Table
SELECT
T1.tp_ID,
T2.Item_Status_Code,
T2.Item_Status_Desc,
T2.Item_Code,
T2.Item_Desc,
T2.Item_Cat_Code,
T2.Item_Cat_Desc,
T2.Item_Cleared_By_No,
T2.Item_Cleared_By_Name
FROM V_Rep_Exit_Checklist T1
CROSS JOIN V_Rep_Exit_Checklist T2
However, you would like to see it as CTE:
;WITH CTE AS (
SELECT * FROM V_Rep_Exit_Checklist
)
INSERT T_Rep_Exit_Checklist_Table
SELECT
T1.tp_ID,
T2.Item_Status_Code,
T2.Item_Status_Desc,
T2.Item_Code,
T2.Item_Desc,
T2.Item_Cat_Code,
T2.Item_Cat_Desc,
T2.Item_Cleared_By_No,
T2.Item_Cleared_By_Name
FROM CTE T1
CROSS JOIN CTE T2
If my assumption is wrong and instead you are trying to just insert all records in the view directly into the table, then why not just a simple INSERT as below?
INSERT T_Rep_Exit_Checklist_Table
SELECT
tp_ID,
Item_Status_Code,
Item_Status_Desc,
Item_Code,
Item_Desc,
Item_Cat_Code,
Item_Cat_Desc,
Item_Cleared_By_No,
Item_Cleared_By_Name
FROM V_Rep_Exit_Checklist
However, if your business requirement is such that you can only insert the records from your view 1 tp_ID at a time, a while statement could be used to replace your cursor:
DECLARE #Records TABLE (tp_ID INT)
INSERT #Records
SELECT tp_ID FROM V_Rep_Exit_Checklist
DECLARE #tp_ID INTEGER
WHILE EXISTS (SELECT * FROM #Records) BEGIN
SET #tp_ID = (SELECT TOP 1 tp_ID FROM #Records)
INSERT T_Rep_Exit_Checklist_Table
SELECT
tp_ID,
Item_Status_Code,
Item_Status_Desc,
Item_Code,
Item_Desc,
Item_Cat_Code,
Item_Cat_Desc,
Item_Cleared_By_No,
Item_Cleared_By_Name
FROM V_Rep_Exit_Checklist
WHERE tp_ID = #tp_ID
DELETE #Records WHERE tp_ID = #tp_ID
END

Need T-SQL Query for Groups and Islands

create table #sample (rowguid int identity ,id_frm int ,id_to int)
insert into #sample values( 1,5)
insert into #sample values( 7,13)
insert into #sample values( 17,20)
In the above table I have values starting Id and Ending Id. I need to prepare a table which has all the numbers falls between starting Id and Ending Id
i have tried it with looping but response is very slow in real world.
any body help me with query ???
This is what I have tried so far...
declare #sql varchar(8000) = '
select top '+cast((select max(id_to) from #sample) as varchar(100))+' identity(int,1,1) as guidid into tally from sysobjects,syscolumns '
exec (#sql)
alter table Tally add slab varchar(10)
create clustered index idx on Tally(guidid)
create clustered index idx on #sample(id_frm asc,id_to desc)
update Tally set slab = rowguid
from #sample join Tally on guidid between id_frm and id_to
delete from Tally where slab is null
select * from Tally
This query works fine with small numbers
But My real time table have 13 digit nos. It through Arithmetic overflow error
Assuming the range id_frm and id_to is relatively small integers, e.g. < 1M, one technique to approach this problem is to create a table with all values in the range and join to it:
WITH lotsOfNumbers AS
(
SELECT ROW_NUMBER() OVER (ORDER BY o1.object_id) AS id
FROM sys.objects o1 CROSS JOIN sys.objects o2
)
INSERT INTO #targetTable
SELECT l.ID
FROM lotsOfNumbers l
INNER JOIN #sample
ON l.ID BETWEEN #sample.id_frm AND #sample.id_to;
SqlFiddle here
A permanent table with the necessary range of ID's and a clustered index on the ID would improve performance, obviously.
Add in a DISTINCT if your ranges overlap, and you don't want duplicates in the result.
If you are able to get a full range of acceptable values into another table, you can use it without looping. The meathod below gets the minimum (1) and maximum (20), and the temporary table named #range will return everything in between.
drop table #sample
drop table #range
create table #sample (id_frm int ,id_to int)
insert into #sample values( 1,5)
insert into #sample values( 7,13)
insert into #sample values( 17,20)
create table #range (id int)
insert into #range select 1
go
insert into #range select top 1 max(id)+ 1 from #range
go 100
declare #min int
declare #max int
set #min= (select min(id_frm ) from #sample )
set #max = (select max(id_to) from #sample )
select * from #range where id between #min and #max

Resources