SQL loop insert using declared table - mysql

I have a declared table which has a lot of data in it... I get the data by doing a select query on my InventoryLogs.. now, what I want is to insert this data on another table called MonthlySalesHistoryDetail... However I don't know how to get the values of my declared table...
this is a stored procedure:
Alter Procedure InsertMonthlySalesHistoryEndDate
#CurrentDate date,
#CreatedByID int,
#LastInsertID int
as
Declare #details table
(
RowID int identity(1,1) primary key,
MonthlySalesHistoryID int,
ItemID int,
MeasurementUnitID int,
QuantitySold numeric(18,4),
QuantityReturned numeric(18,4),
TotalSoldAmount numeric(18,4),
TotalReturnedAmount numeric(18,4)
)
Insert Into #details
(
MonthlySalesHistoryID,
ItemID,
MeasurementUnitID,
QuantitySold,
QuantityReturned,
TotalSoldAmount,
TotalReturnedAmount
)
SELECT
#LastInsertID,
il.ItemID,
il.MeasurementUnitID,
SUM(il.Quantity) as QuantitySold,
ISNULL((SELECT SUM(Quantity) FROM InventoryLogs WHERE TransactionType = 15 AND CAST(InventoryLogDate as date) = #CurrentDate),0) as QuantityReturned,
SUM(il.ComputedCost) as TotalSoldAmount,
ISNULL((SELECT SUM(ComputedCost) FROM InventoryLogs WHERE TransactionType = 15 AND CAST(InventoryLogDate as date) = #CurrentDate),0) as TotalReturnedAmount
FROM InventoryLogs il
WHERE il.TransactionType = 9 AND CAST(InventoryLogDate as date) = #CurrentDate
GROUP BY il.ItemID, il.MeasurementUnitID
declare #count int = (SELECT COUNT(*) FROM #details)
declare #counter int = 0
WHILE(#count > #counter)
BEGIN
SET #counter = #counter + 1
SELECT * FROM #details d Where d.RowID = #counter
INSERT INTO MonthlySalesHistoryDetails
(
MonthlySalesHistoryID,
ItemID,
MeasurementUnitID,
QuantitySold,
QuantityReturned,
TotalSoldAmount,
TotalReturnedAmount
)
VALUES
(
//I want to get the values of my
//SELECT * FROM #details d Where d.RowID = #counter here..
)
END
thanks in advance....

I didn't know that it was possible to do this insert... I thought it was only good for declared table
INSERT INTO MonthlySalesHistoryDetails
(
MonthlySalesHistoryID,
ItemID,
MeasurementUnitID,
QuantitySold,
QuantityReturned,
TotalSoldAmount,
TotalReturnedAmount
)
SELECT
d.MonthlySalesHistoryID,
d.ItemID,
d.MeasurementUnitID,
d.QuantitySold,
d.QuantityReturned,
d.TotalSoldAmount,
d.TotalReturnedAmount
FROM #details d Where d.RowID = #counter

Related

Stored procedure is too slow in mysql

I have a routine. But it' s too slow. How can I improve the query?
My records: http://www.sqlfiddle.com/#!9/14cceb/1/0
My query:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE example.ssa()
BEGIN
drop table if exists gps_table;
drop table if exists exam_datas;
CREATE TEMPORARY TABLE gps_table(ID int PRIMARY KEY AUTO_INCREMENT,timei
int,
trun_date_time datetime, tadd_meter int, tin_here int null);
insert into gps_table(timei,trun_date_time,tadd_meter,tin_here) select
imei, run_date_time, add_meter, in_here from example_table;
CREATE TEMPORARY TABLE exam_datas(ID int PRIMARY KEY AUTO_INCREMENT,vimei
int, vbas_run_date_time datetime, vbit_run_date_time datetime, vdifff int);
select tin_here from gps_table limit 1 into #onceki_durum;
select count(id) from gps_table into #kayit_sayisi;
set #i = 1;
set #min_mes = 0;
set #max_mes = 0;
set #frst_id = 0;
set #imei = 0;
set #run_date_time = '0000-00-00 00:00:00';
set #run_date_time2 = '0000-00-00 00:00:00';
myloop: WHILE (#i <= #kayit_sayisi) DO
select tin_here from gps_table where id = #i into #in_here_true;
if (#in_here_true = 1) then
select id,trun_date_time, tadd_meter from gps_table where id = #i into #frst_id,#run_date_time2, #min_mes;
select id from gps_table where id > #frst_id and tin_here =0 order by id asc limit 1 INTO #id;
SET #id = #id-1;
select id, timei, trun_date_time, tadd_meter from gps_table
where id = #id and tin_here =1 limit 1 into #i, #imei, #run_date_time, #max_mes;
if(#i-#frst_id>3) then
set #i:=#i+1;
insert into exam_datas(vimei,vbas_run_date_time,vbit_run_date_time,vdifff) Values (#imei, #run_date_time2, #run_date_time, #max_mes-#min_mes);
SELECT * FROM exam_datas;
SET #asd =1;
elseif 1=1 then
set #i:=#i+1;
End if;
ELSEIF 1=1
THEN SET #i:=#i+1;
End if;
IF (#i = #kayit_sayisi)
THEN set #tamam =1; LEAVE myloop;
END IF;
END WHILE myloop;
select DISTINCT * from exam_datas;
drop table if exists exam_datas;
drop table if exists gps_table;
END
I need: id= 6 first true and id= 11 last_true
firs_trure - last_true = 304-290= 14
id=14 first true and id=18 last_true
firs_true - last_true = 332-324= 8
This routine is too slow.
MySql version is 5.7 and There are 2 milions record in the table.
UPDATE:
Query is here. HERE
Thank you #LukStorms
It's possible to get such results in 1 query.
Thus avoiding a WHILE loop over records.
This example works without using window functions. Just using variables inside the query to calculate a rank. Which is then used to get the minimums and maximums of the groups.
select
imei,
min(run_date_time) as start_dt,
max(run_date_time) as stop_dt,
max(add_meter) - min(add_meter) as diff
from
(
select imei, id, run_date_time, add_meter, in_here,
case
when #prev_imei = imei and #prev_ih = in_here then #rnk
when #rnk := #rnk + 1 then #rnk
end as rnk,
#prev_imei := imei as prev_imei,
#prev_ih := in_here as prev_ih
from example_table t
cross join (select #rnk := 0, #prev_ih := null, #prev_imei := null) vars
order by imei, id, run_date_time
) q
where in_here = 1
group by imei, rnk
having count(*) > 4
order by imei, min(id);
In the procedure such query can be used to fill that final temporary table.
A test on db<>fiddle here

Loop based on parameter value

I need to create a temporary table that is populated based on two parameters:
declare #Start date = '01/01/2015'
declare #End date = '12/31/2015'
The temporary table should have a column that will capture YYYYMM for all the years and month that are between #Start and #End parameter.
Here's what I have so far. I want to stop it at 201412 and then start again at 201501. Instead, this loop keeps going in increment of plus 1 (I do not want to see 201413..so on):
declare #Start date = '01/01/2014'
declare #End date = '12/31/2015'
declare #monthstart as int
declare #monthend as int
declare #increment as int
set #monthstart = (SELECT LEFT(CONVERT(varchar, #Start,112),6))
set #monthend = (SELECT LEFT(CONVERT(varchar, #End,112),6))
create table #datetemp (RelevantYYYYMM int)
insert into #datetemp values (#monthstart)
set #increment = #monthstart
While #increment < #monthend
BEGIN
set #increment = (select Max(RelevantYYYYMM) + 1 from #datetemp)
insert into #datetemp values (#increment)
set #increment = (select Max(RelevantYYYYMM) from #datetemp)
IF (select Max(RelevantYYYYMM) from #datetemp) > #monthend
Break
else
continue
END
select * from #datetemp
You can use tally table and avoid loop:
CREATE TABLE #datetemp (RelevantYYYYMM INT);
DECLARE #Start DATE = '01/01/2015', #End DATE = '12/31/2015';
WITH tally_table AS
(
SELECT TOP 1000 rn = ROW_NUMBER() OVER(ORDER BY name) - 1
FROM master..spt_values
)
INSERT INTO #datetemp(RelevantYYYYMM)
SELECT LEFT(CONVERT(varchar, DATEADD(month, rn, #Start),112),6)
FROM tally_table
WHERE YEAR(DATEADD(month, rn, #Start)) <= YEAR(#End)
AND MONTH(DATEADD(month, rn, #Start)) <= MONTH(#End)
SELECT *
FROM #datetemp;
LiveDemo

Rewrite Stored Procedure

I have the next stored procedure which inserts values into 2 tables. To the 2nd table I insert id's of 2 last inserts from 1st table
However, I would like to rewrite it with one query instead of using temp table and while.
CREATE PROCEDURE CurrencyExhange
AS
DECLARE #TmpTable Table
(
ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
BillID int,
Amount decimal,
Rate decimal,
Date date
)
INSERT INTO #TmpTable
SELECT T.[BillID]
,[Amount]
,CR.Rate
,CR.Date
FROM [FinanceLabkovich].[dbo].[Transactions] T
JOIN [FinanceLabkovich].[dbo].Bills B ON B.BillID = T.BillID
JOIN [FinanceLabkovich].[dbo].Currencies C ON C.CurrencyID=B.CurrencyID
JOIN [FinanceLabkovich].[dbo].CurrencyRates CR ON CR.CurrencyRateID=FinanceLabkovich.dbo.GetRate(T.Date)
WHERE LOWER(C.Name)='usd' AND T.Income=1
ORDER BY T.Date
DECLARE #ToBillID int = (SELECT BillID FROM [FinanceLabkovich].[dbo].Bills B WHERE B.Name='Purse')
DECLARE #i int = (SELECT MIN(Id) FROM #TmpTable)
DECLARE #maxId int = (SELECT MAX(Id) FROM #TmpTable)
DECLARE #TransactionID int, #ToTransactionID int, #Amount decimal
DECLARE #date date
WHILE (#i<=#maxId)
BEGIN
SET #date = (SELECT Date FROM #TmpTable WHERE ID=#i)
SET #Amount = (SELECT AmountUSD FROM [FinanceLabkovich].[dbo].Cashflow WHERE Date=#date)
IF #Amount > 0
BEGIN
INSERT INTO [FinanceLabkovich].[dbo].[Transactions] (Name,BillID,ToBillID,Amount,Date,Income)
SELECT "Name"='Currency exhange'
,BillID
,#ToBillID
,#Amount
,T.Date
,"Income"=0
FROM #TmpTable T
WHERE ID=#i
SET #TransactionID = ##IDENTITY
INSERT INTO [FinanceLabkovich].[dbo].[Transactions] (Name,BillID,ToBillID,Amount,Date,Income)
SELECT "Name"='Currency exhange'
,#ToBillID
,BillID
,#Amount*Rate AS Total
,Date
,"Income"=1
FROM #TmpTable WHERE ID=#i
SET #ToTransactionID = ##IDENTITY
INSERT INTO [FinanceLabkovich].[dbo].[Transfers]
SELECT #TransactionID, #ToTransactionID
END
SET #i += 1
END
Any help appreciated.

Need help to inserting 100 records in loop, continue where it stop from and break once the records are completed.

Need help to inserting 100 records in loop, continue where it stop from and break once the records are completed.
Alter PROCEDURE ETL.ETLPurge #PurgeYear INT
AS
BEGIN
DECLARE #BatchId INT = (SELECT BatchId FROM Tracker)
declare #Count int
declare #batchsize int
set #batchsize = 100
--set #Count = ##rowcount
SELECT DISTINCT IDENTITY(INT,1,1) AS ID, MC.ID
INTO #tmp
FROM Contact MC
JOIN Extract CE
ON MC.ExtractID = CE.ExtractID
LEFT JOIN Application A
ON MC.ID = A.ID
WHERE CE.Year < #PurgeYear
AND A.ApplicationId IS NULL
--declare #counter bigint
--set #counter = 1
--while #counter < 500
--Begin
--while 1 = 1
--begin
Create NONCLUSTERED INDEX nix_ID
on #tmp(ID)
--while 1=1
--begin
INSERT
--Top (#batchsize)
INTO Table1 (Values ………)
(
SELECT top (#batchsize)
#BatchID,
Values ……..)
FROM Contact MC
inner join
#tmp TK on MC.ContactID = TK.ContactID
--where TK.ID between #batchsize and #ctr + 1
)
if ##ROWCOUNT < #batchsize
break
end
-- --continue
-- --if ##ROWCOUNT = 0
-- Break
end
--end
--number of rows inserted should equal number of rows deleted.
Ok.
Here is my sample.
What happened to me is that my dba "team" .. screwed up setting Replication for us.
So .. over the weekend, working like dogs.... we had to write some code to "pull over" records from a source database to a destination database, where the structure of the database was the same. We had to fake-out some replication.
We had 8,000,000 rows, and we would pull them over 10,000 at a time.
Below, I have about 1000 rows, and set the "number of rows to pull at one time" to 333.
I also put a #MaximumLoopCounter as a "just in case". I didn't want to accidentally create a endless loop.
The sample below bases its "while" logic on "while exists (some records on the source-database-table that are not in the destination-database-table)"...keep grabbing those records.
I'm trying to help you answer your question. In our case, we finally got replication working correctly, and we were able to abandon these scripts. It was NOT a fun weekend.
/* SETUP */
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[CodeCategorySourceTable]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE [dbo].[CodeCategorySourceTable]
END
GO
CREATE TABLE [dbo].[CodeCategorySourceTable] (
CodeCategoryUUID [uniqueidentifier] not null default NEWSEQUENTIALID() ,
CodeCategoryName varchar(64) not null
)
GO
ALTER TABLE [dbo].[CodeCategorySourceTable] ADD CONSTRAINT PK_CodeCategorySourceTable_CodeCategoryUUID
PRIMARY KEY CLUSTERED (CodeCategoryUUID)
GO
ALTER TABLE [dbo].[CodeCategorySourceTable] ADD CONSTRAINT CK_CodeCategorySourceTable_CodeCategoryName_UNIQUE
UNIQUE (CodeCategoryName)
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[CodeCategoryDestinationTable]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE [dbo].[CodeCategoryDestinationTable]
END
GO
CREATE TABLE [dbo].[CodeCategoryDestinationTable] (
CodeCategoryUUID [uniqueidentifier] not null default NEWSEQUENTIALID() ,
CodeCategoryName varchar(64) not null
)
GO
ALTER TABLE [dbo].[CodeCategoryDestinationTable] ADD CONSTRAINT PK_CodeCategoryDestinationTable_CodeCategoryUUID
PRIMARY KEY CLUSTERED (CodeCategoryUUID)
GO
ALTER TABLE [dbo].[CodeCategoryDestinationTable] ADD CONSTRAINT CK_CodeCategoryDestinationTable_CodeCategoryName_UNIQUE
UNIQUE (CodeCategoryName)
GO
declare #AlreadyExistingCodeCategoryUUID01 uniqueidentifier
declare #AlreadyExistingCodeCategoryUUID03 uniqueidentifier
declare #AlreadyExistingCodeCategoryUUID02 uniqueidentifier
declare #AlreadyExistingOldCodeCategoryName01 varchar(64)
declare #AlreadyExistingOldCodeCategoryName02 varchar(64)
declare #AlreadyExistingOldCodeCategoryName03 varchar(64)
declare #AlreadyExistingNewCodeCategoryName01 varchar(64)
declare #AlreadyExistingNewCodeCategoryName02 varchar(64)
declare #AlreadyExistingNewCodeCategoryName03 varchar(64)
select #AlreadyExistingCodeCategoryUUID01 = NEWID(), #AlreadyExistingCodeCategoryUUID02 = NEWID(), #AlreadyExistingCodeCategoryUUID03 = NEWID()
select #AlreadyExistingNewCodeCategoryName01 = 'NewOne', #AlreadyExistingNewCodeCategoryName02 = 'NewTwo', #AlreadyExistingNewCodeCategoryName03 = 'NewThree'
select #AlreadyExistingOldCodeCategoryName01 = 'OldOne', #AlreadyExistingOldCodeCategoryName02 = 'OldTwo', #AlreadyExistingOldCodeCategoryName03 = 'OldThree'
Insert Into [dbo].[CodeCategorySourceTable] ( CodeCategoryUUID , CodeCategoryName )
Select top 1000 NEWID() , convert(varchar(40), NEWID()) + 'Name' from dbo.sysobjects so1 cross join dbo.sysobjects so2
Insert Into [dbo].[CodeCategorySourceTable] ( CodeCategoryUUID , CodeCategoryName )
select #AlreadyExistingCodeCategoryUUID01, #AlreadyExistingNewCodeCategoryName01
UNION ALL select #AlreadyExistingCodeCategoryUUID02, #AlreadyExistingNewCodeCategoryName02
UNION ALL select #AlreadyExistingCodeCategoryUUID03, #AlreadyExistingNewCodeCategoryName03
select count(*) from [dbo].[CodeCategorySourceTable] as CodeCategorySourceTableCOUNT
Insert Into [dbo].[CodeCategoryDestinationTable] ( CodeCategoryUUID , CodeCategoryName )
select #AlreadyExistingCodeCategoryUUID01, #AlreadyExistingOldCodeCategoryName01
UNION ALL select #AlreadyExistingCodeCategoryUUID02, #AlreadyExistingOldCodeCategoryName02
UNION ALL select #AlreadyExistingCodeCategoryUUID03, #AlreadyExistingOldCodeCategoryName03
select count(*) from [dbo].[CodeCategoryDestinationTable] as CodeCategoryDestinationTableCOUNT
/* USP */
print '[uspCodeCategoryReplicateReplacer]'
go
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[uspCodeCategoryReplicateReplacer]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[uspCodeCategoryReplicateReplacer]
Go
/*
declare #numberRowsAffected int
declare #ErrorNumber int
exec [dbo].[uspCodeCategoryReplicateReplacer] #numberRowsAffected output , #ErrorNumber output
print #numberRowsAffected
print #ErrorNumber
print ''
*/
CREATE PROCEDURE [dbo].[uspCodeCategoryReplicateReplacer] (
#numberRowsAffected int output
,
#ErrorNumber int output
)
AS
SET NOCOUNT ON
select #ErrorNumber = 0
declare #ErrorTracker int
declare #insertRowCount int
declare #updateRowCount int
select #insertRowCount = 0
select #updateRowCount = 0
declare #CurrentInsertCount int
declare #ManualReplicationRowCount int
select #ManualReplicationRowCount = 333
declare #MaximumLoopCounter int
select #MaximumLoopCounter = 10000
while (#MaximumLoopCounter > 0) and exists
(
Select
TOP 1 null
from [dbo].[CodeCategorySourceTable] sourceTable with (nolock)
where not exists
(
select null from [dbo].[CodeCategoryDestinationTable] destinationTable with (nolock)
Where
destinationTable.CodeCategoryUUID = sourceTable.CodeCategoryUUID
)
)
BEGIN
select #MaximumLoopCounter = #MaximumLoopCounter - 1
/* DELETE FROM [dbo].[CodeCategoryDestinationTable] */
SET NOCOUNT OFF
Insert into [dbo].[CodeCategoryDestinationTable]
(
CodeCategoryUUID,
CodeCategoryName
)
Select
TOP (#ManualReplicationRowCount)
CodeCategoryUUID,
CodeCategoryName
from [dbo].[CodeCategorySourceTable] sourceTable with (nolock)
where not exists
(
select null from [dbo].[CodeCategoryDestinationTable] destinationTable with (nolock)
Where
destinationTable.CodeCategoryUUID = sourceTable.CodeCategoryUUID
)
SELECT #CurrentInsertCount = ##ROWCOUNT , #ErrorTracker = ##ERROR
select #insertRowCount = #insertRowCount + #CurrentInsertCount
if #ErrorTracker <> 0
BEGIN
select #ErrorNumber = #ErrorTracker
select #MaximumLoopCounter = 0 /*Bail Out !!!*/
END
SET NOCOUNT ON
END /*End While Loop*/
print '/Before Look [dbo].[CodeCategoryDestinationTable] */'
select * from [dbo].[CodeCategoryDestinationTable]
SET NOCOUNT OFF
/* A little extra. Update any non-surrogate-key values... We did not do this, but I leave it here as for kicks */
Update [dbo].[CodeCategoryDestinationTable]
Set
/*CodeCategoryUUID = vart.CodeCategoryUUID,*/
CodeCategoryName = sourceTable.CodeCategoryName
From
[dbo].[CodeCategoryDestinationTable] destinationTable, [dbo].[CodeCategorySourceTable] sourceTable
Where
/*Relationship*/
destinationTable.CodeCategoryUUID = sourceTable.CodeCategoryUUID
/*Filter*/
and destinationTable.CodeCategoryName <> sourceTable.CodeCategoryName
SELECT #updateRowCount = ##ROWCOUNT
SET NOCOUNT ON
print '/After Look [dbo].[CodeCategoryDestinationTable] */'
select * from [dbo].[CodeCategoryDestinationTable]
print '/#insertRowCount COUNT/'
print #insertRowCount
print '-------------------------'
print '/#updateRowCount COUNT/'
print #updateRowCount
print '-------------------------'
SELECT #numberRowsAffected = #insertRowCount + #updateRowCount
print '/ [dbo].[CodeCategoryDestinationTable] COUNT/'
print #numberRowsAffected
print '-------------------------'
SET NOCOUNT OFF
GO
/*GRANT EXECUTE ON dbo.uspCodeCategoryReplicateReplacer TO $(DBUSERNAME)*/
GO
/* Improvement , encapsulate the ManualReplicationRowCount "getter" so it can be changed in one place */
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[uspInternalSettingGetManualReplicationRowCount]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[uspInternalSettingGetManualReplicationRowCount]
GO
/*
--START TEST
declare #returnCode int
declare #ManualReplicationRowCount int
EXEC #returnCode = dbo.uspInternalSettingGetManualReplicationRowCount #ManualReplicationRowCount output
print #ManualReplicationRowCount
print '/#returnCode/'
print #returnCode
*/
CREATE PROCEDURE [dbo].[uspInternalSettingGetManualReplicationRowCount] (
#ManualReplicationRowCount int output --return
)
AS
SET NOCOUNT ON
select #ManualReplicationRowCount = 333
SET NOCOUNT OFF
GO

What can I use instead of #Temp table in sql function

Here is my sql query.
CREATE FUNCTION UF_GetOrderProducts
(
#OrderId int
)
RETURNS VARCHAR(500)
AS
BEGIN
SELECT Identity(int,1,1) ID, ProductId INTO #Temp FROM OrderProduct WHERE OrderId = #OrderId
Declare #Id int,
#Count int,
#LoopCount int,
#ProductList VARCHAR(500),
#ProductListTemp VARCHAR(500)
SET #Count = (Select Count(*) From #Temp)
SET #LoopCount = 1
SET #ProductList = ''
WHILE #LoopCount <= #Count
BEGIN
SET #ProductListTemp =( SELECT Name FROM Product WHERE ProductId =(Select ProductId from #Temp Where ID = #LoopCount))
SET #ProductList +=#ProductListTemp + '<br/>'
Set #LoopCount=#LoopCount + 1
END
DROP TABLE #Temp
RETURN #ProductList
END
GO
I have to loop in #Temp Table. Do you have any other suggestions?
Instead of temp table you can use a table variable.
declare #Temp TABLE (ID int identity, ProductId int)
insert into #Temp(ProductId)
select ProductId
from OrderProduct
where OrderId = #OrderId
But you could rewrite your function without a loop.
Something like this should do what you want.
create function IF_GetOrderProducts
(
#OrderId int
)
returns varchar(500)
as
begin
return
(
select Name+'<br/>'
from Product as P
inner join OrderProduct as OP
on P.ProductId = OP.ProductId
where OP.OrderId = #OrderId
for xml path(''), type
).value('.', 'varchar(500)')
end