У меня две таблицы T1 и T2 в MySQL Community 5.7 DB
T1: (ProdID varchar, другие столбцы INT)
ProdID Request Available Stock
------------------------------------
Prod1 17 50 33
Prod2 16 40 24
Prod43 0 10 10
T2: (CompID varchar, другие столбцы INT)
CompID Prod1 Prod2 Prod43 Request Available Stock
-------------------------------------------------------------
Comp1 3 1 NULL 67 100 33
Comp2 NULL 4 NULL 64 100 36
Comp48 3 5 2 131 100 -31
T1 поддерживает обработку готовой продукции. T2 содержит количество компонентов, необходимых для определенных продуктов, а также относительное перемещение.
Мне нужно создать процедуру, которая обновляет столбец запроса в таблице T2 следующим образом:
T2.Request = prod1 * (T1.Request, где ProdID = Prod1) + Prod2 * (T1.Request, где ProdID = Prodt2) и т.д.
Не зная, как это сделать в SQL, я сделал это в VBA на Excel ("HMWComp" обновил T2 полностью), и он работает, но операторы жалуются, что операция занимает пару секунд. Так как строк меньше 50, и самое большее может быть 3-4 одновременных соединения, я задавался вопросом, сделает ли операцию на сервере в mysql быстрее выполнение операции.
Если да, как я могу это сделать?
Код VBA:
Option Explicit
public SRow as integer
public Conn as ADODB.Connection
public RS1 as ADODB.Recordset
Public Sub HMWComp()
Call ConnectDB' An external procedure to connect to DB...'
SRow = 1
Dim rsqui As ADODB.Recordset
Set rsqui = New ADODB.Recordset
rsqui.Open "select CompID from T2;", Conn, adOpenDynamic
Dim Numero As Integer
rsqui.MoveFirst
Do
Numero = HowManyComponents(rsqui!CompID)
Conn.Execute "update T2 set request=" & Numero & " where CompID=" & rsqui!CompID & ";"
rsqui.MoveNext
Loop Until rsqui.EOF
rsqui.Close
End Sub
Public Function HowManyComponents(ByVal Component As String) As Integer
Dim WSDest as Worksheet
Set WSdest = ThisWorkbook.Sheets("Temp")
WSdest.Cells.Clear
Set RS1 = New ADODB.Recordset
RS1.Open "select column_name from information_schema.columns where table_name='T2' and column_name<>'CompID' and column_name<>'Request' and column_name<>'Available' and column_name<>'Stock';", Conn, adOpenDynamic
RS1.MoveFirst
Do
Set RSF = New ADODB.Recordset
RSF.Open "select " & RS1(0) & " from T2 where CompID=" & Component & ";", Conn, adOpenStatic
If IsNull(RSF(0)) = False Then
With WSdest
.Cells(SRow, 1) = RSF(0)
RSF.Close
Set RSF = New ADODB.Recordset
RSF.Open "select Request from T1 where ProdiD='" & RS1(0) & "';", Conn, adOpenStatic
If IsNull(RSF(0)) = False Then
.Cells(SRow, 2) = RSF(0)
Else
.Cells(SRow, 2) = 0
End If
RSF.Close
.Cells(SRow, 3) = .Cells(SRow, 1) * .Cells(SRow, 2)
End With
SRow = SRow + 1
Else
RSF.Close
End If
RS1.MoveNext
Loop Until RS1.EOF
RS1.Close
HowManyComponents = WorksheetFunction.Sum(WSdest.Columns(3))
Exit Function
End Function
Я попытался написать процедуру, но, к сожалению, она только обновляет (точно) последнюю запись. Как правильно обрабатывать циклы?
хранимая процедура sql:
BEGIN
DECLARE done INT DEFAULT FALSE;
declare col_name varchar(20);
declare CodName varchar(30);
declare NR int;
declare CR int;
declare PERC int;
declare TOT int;
declare cur1 CURSOR FOR
select column_name from information_schema.columns where table_name='T2' and column_name<>'CompID';
declare cur2 cursor for
select codice from T2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
set NR=(select count(*) from T2);
open cur1;
set CR=0;
truncate table debug_table;
read_loop: loop
fetch cur1 into col_name;
if done then leave read_loop; end if;
set TOT=0;
set CR=CR+1;
set @sqlstr=concat('select @QC := richieste from T1 where ProdID=',char(39),col_name,char(39),';');
insert into debug_table(id,msg1) values(cr,@sqlstr);
prepare stmt from @sqlstr;
execute stmt ;
deallocate prepare stmt;
open cur2;
write_loop: loop
set PERC=0;
if done then leave write_loop; end if;
fetch cur2 into CodName;
set @sqlstr=concat('select @QP := coalesce(',col_name,',0) from T2 where CompID=',char(39),CodName,char(39),';');
update debug_table set msg2=@sqlstr where id=cr;
prepare stmt from @sqlstr;
execute stmt ;
deallocate prepare stmt;
set PERC=@QC*@QP;
set TOT=TOT+PERC;
end loop;
close cur2;
set @sqlstr=concat('update T2 set richiesti=',tot,' where CompID=',char(39),CodName,char(39),';');
update debug_table set msg3=@sqlstr where id=cr;
prepare stmt from @sqlstr;
execute stmt ;
deallocate prepare stmt;
end loop;
END
create table #t1 (ProdID varchar(10), Request int, Available int,Stock int)
insert #t1 values
( 'Prod1' , 17 , 50 ,33)
,( 'Prod2' , 16 , 40 ,24)
,( 'Prod43' , 0 , 10 ,10)
create table #t2 (CompID varchar(10), Prod1 int, Prod2 int, Prod43 int, Request int, Available int, Stock int)
insert #t2 values
('Comp1' , 3 , 1 ,NULL, 00 , 100 , 33) -- 00 for request. After the sp, these values are will be updated.
, ('Comp2' , NULL, 4 ,NULL, 00 , 100 , 36) -- 00 for request. After the sp, these values are will be updated.
, ('Comp48', 3 , 5 , 2 , 00 , 100 ,-31) -- 00 for request. After the sp, these values are will be updated.
create procedure updateRequest as
begin
select CompID, sum(value*t1.Request) val into #update from (
select *
from #t2
unpivot (value for Prods in ([prod1],[prod2],[prod43])) up
) t2
join #t1 t1
on t2.Prods = t1.ProdID
group by CompID
update t
set t.Request = u.val
from #t2 t
join #update u
on t.CompID = u.CompID
select * from #t2
drop table #update
end
select * from #t2
exec updateRequest
Верните меня, если запрос нуждается в обновлениях.
Вы должны попытаться использовать подзапрос с таблицей INFORMATION_SCHEMA
, где вы можете установить условия для имен полей таблицы T2
:
(SELECT COLUMN_NAME AS ProdID
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA='yourdatabasename'
AND TABLE_NAME='T2'
AND TABLE_NAME LIKE 'Prod%') TAUX
Это, однако, остается сложной задачей из-за неправильной нормализации схемы БД.