13. august 2024 - 15:08Der er
20 kommentarer og 1 løsning
Auto Faktura..
Hej jeg er ved at lave et faktura system som gerne skulle kun lave order når et domain er ved at udløbe, men det driller mig en del jeg kan bare ikke få mit loop til at virker.
Jeg lave en TEMPORARY TABLE som jeg smider alle min orderline ned i da den del virker
går jeg vider og vil gerne loop min TEMPORARY TABLE gemmen sådan at den tager alle order til kunde 1 og oprette en faktura til den kunde her efter tager den så alle orderline der tilhøre den kunde og smider i orderline
men af en eller anden grund laver den kun en faktura. og laver så ikke order 2.. selv om den er i TEMPORARY TABLE..
håber der er en der kan se fejl !!!
BEGIN DECLARE done INT DEFAULT False; DECLARE vDebitorID INT; DECLARE vLineType ENUM('Line', 'Text'); DECLARE vLineNr VARCHAR(15); DECLARE vLineText VARCHAR(250); DECLARE vLinePrice DECIMAL(12,2); DECLARE vLineCount INT; DECLARE vLineCountText VARCHAR(20); DECLARE tempCur CURSOR FOR SELECT DISTINCT DebitorID FROM temp_orderline; DECLARE templineCur CURSOR FOR SELECT AutoorderType,AutoorderNr,AutoorderText,AutoorderPrice,AutoorderCount,AutoorderCountText FROM temp_orderline WHERE DebitorID=vDebitorID; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = True; CREATE TEMPORARY TABLE temp_orderline ( `DebitorID` int(11) NOT NULL, `AutoorderType` enum('Line','Text') NOT NULL, `AutoorderNr` varchar(15) NOT NULL, `AutoorderText` varchar(250) NOT NULL, `AutoorderPrice` decimal(12,2) NOT NULL, `AutoorderCount` int(10) NOT NULL, `AutoorderCountText` varchar(20) NOT NULL );
INSERT INTO `temp_orderline` (`DebitorID`, `AutoorderType`, `AutoorderNr`, `AutoorderText`, `AutoorderPrice`, `AutoorderCount`, `AutoorderCountText`) SELECT `system_debitor`.`DebitorID` AS DebitorID,'Line' AS AutoorderType,`system_product`.`ProductNr` AS AutoorderNr,REPLACE(REPLACE(REPLACE(`system_product`.`ProductText`,'{{domainname}}',`system_debitor_domain`.`DomainName`),'{{periodefrom}}',DATE_FORMAT(ifnull(`system_debitor_domain`.`DomainExpire`,`system_debitor_domain`.`DomainCreate`),'%d.%m.%Y')),'{{periodeto}}',DATE_FORMAT(ADDDATE(ifnull(`system_debitor_domain`.`DomainExpire`,`system_debitor_domain`.`DomainCreate`), INTERVAL `system_debitor_domain`.`DomainPeriode`*365 DAY),'%d.%m.%Y')) as AutoorderText,`system_product`.`ProductPrice` AS AutoorderPrice,`system_debitor_domain`.`DomainPeriode` AS AutoorderCount,`system_product`.`ProductEnhed` AS AutoorderCountText FROM `system_debitor_domain` INNER JOIN `system_debitor` ON `system_debitor`.`DebitorID`=`system_debitor_domain`.`DebitorID` AND `system_debitor_domain`.`DomainStatus`='Active' AND (ISNULL(`system_debitor_domain`.`DomainExpire`) OR DATEDIFF(`system_debitor_domain`.`DomainExpire`,CURRENT_DATE()) <=60) INNER JOIN `system_product_domain` ON `system_product_domain`.`DomainTLD`=SUBSTRING(`system_debitor_domain`.`DomainName`, LOCATE('.',`system_debitor_domain`.`DomainName`)) AND FIND_IN_SET((IF(ISNULL(`DomainExpire`),IF(`DomainUpdate`>`DomainCreate`,'Move','Create'),'Renew')),`system_product_domain`.`ProductType`) INNER JOIN `system_product` ON `system_product`.`ProductID`=`system_product_domain`.`ProductID`;
OPEN tempCur; debitor_loop: LOOP FETCH tempCur INTO vDebitorID; IF done THEN LEAVE debitor_loop; END IF; START TRANSACTION; SET @p0='N14'; INSERT INTO `system_debitor_order` (`DebitorID`, `OrderType`, `OrderNr`, `OrderCreate`, `OrderPayDay`) VALUES (vDebitorID, 'Invoice', NULL, CURRENT_DATE(), `MakeDay`(@p0)); SET @orderId = LAST_INSERT_ID(); OPEN templineCur; templine_loop: LOOP FETCH templineCur INTO vLineType, vLineNr, vLineText, vLinePrice, vLineCount, vLineCountText; IF done THEN LEAVE templine_loop; END IF; INSERT INTO `system_debitor_orderline` (`orderid`, `orderlinetype`, `orderlinenr`, `orderlinetext`, `orderlineprice`, `orderlinecount`, `orderlinecounttext`) VALUES (@orderId, vLineType, vLineNr, vLineText, vLinePrice, vLineCount, vLineCountText); END LOOP; CLOSE templineCur; COMMIT; END LOOP debitor_loop; CLOSE tempCur; SELECT * FROM `temp_orderline`;
Som jeg husker det holdes en cursor ikke åben efter en COMMIT. Du kan evt. prøve at flytte din COMMIT en linje længere ned.
Hvis det så virker, vil jeg også mene at det **altid** er noget rod at bruge cursor i SQL. Det kan dog være måske fornuftigt at lave den beregning i SQL - bare på en anden måde.
SQL er et fremragende query sprog - kolonne udvælgelse, joins, where betingelser, gruppering etc..
Men SQL er et elendigt programmerings sprog. Execute en SELECT og en while løkke som itererer over result set er pænere end CURSOR og FETCH. En collection er pænere end en temporær tabel.
Der er en grund til at mange databaser understøtter stored procedures i et traditionelt sprog fremfor kun SQL.
Oracle DB (Java, C#), IBM DB2 (Java), MS SQLServer (C#), Sybase ASE (Java), Derby (Java), PostgreSQL (Perl, Python, Tcl) etc.. MySQL 9 i betalings version understøtter JavaScript.
Hvilket naturligvis ikke hjælper dig.
Det er svært at gennemskue den SQL.
Eriks forslag med at ændre transaction bracket er nem at teste. Jeg ville nok tage det et skridt videre og lave det hele i en transaktion. START TRANSACTION aller først. COMMIT aller sidst.
For det første kan det undgå eventuelle SQL kode problemer. Men derudover i tilfælde af at der sker en fejl i scriptet formoder jeg at du faktisk helst vil have det hele rullet tilbage og starte forfra.
BEGIN DECLARE done INT DEFAULT 0; DECLARE vDebitorID INT; DECLARE vLineType ENUM('Line', 'Text'); DECLARE vLineNr VARCHAR(15); DECLARE vLineText VARCHAR(250); DECLARE vLinePrice DECIMAL(12,2); DECLARE vLineCount INT; DECLARE vLineCountText VARCHAR(20); DECLARE tempCur CURSOR FOR SELECT DISTINCT DebitorID FROM temp_orderline; DECLARE templineCur CURSOR FOR SELECT AutoorderType,AutoorderNr,AutoorderText,AutoorderPrice,AutoorderCount,AutoorderCountText FROM temp_orderline WHERE DebitorID=vDebitorID; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; CREATE TEMPORARY TABLE temp_orderline ( `DebitorID` int(11) NOT NULL, `AutoorderType` enum('Line','Text') NOT NULL, `AutoorderNr` varchar(15) NOT NULL, `AutoorderText` varchar(250) NOT NULL, `AutoorderPrice` decimal(12,2) NOT NULL, `AutoorderCount` int(10) NOT NULL, `AutoorderCountText` varchar(20) NOT NULL );
INSERT INTO `temp_orderline` (`DebitorID`, `AutoorderType`, `AutoorderNr`, `AutoorderText`, `AutoorderPrice`, `AutoorderCount`, `AutoorderCountText`) SELECT `system_debitor`.`DebitorID` AS DebitorID,'Line' AS AutoorderType,`system_product`.`ProductNr` AS AutoorderNr,REPLACE(REPLACE(REPLACE(`system_product`.`ProductText`,'{{domainname}}',`system_debitor_domain`.`DomainName`),'{{periodefrom}}',DATE_FORMAT(ifnull(`system_debitor_domain`.`DomainExpire`,`system_debitor_domain`.`DomainCreate`),'%d.%m.%Y')),'{{periodeto}}',DATE_FORMAT(ADDDATE(ifnull(`system_debitor_domain`.`DomainExpire`,`system_debitor_domain`.`DomainCreate`), INTERVAL `system_debitor_domain`.`DomainPeriode`*365 DAY),'%d.%m.%Y')) as AutoorderText,`system_product`.`ProductPrice` AS AutoorderPrice,`system_debitor_domain`.`DomainPeriode` AS AutoorderCount,`system_product`.`ProductEnhed` AS AutoorderCountText FROM `system_debitor_domain` INNER JOIN `system_debitor` ON `system_debitor`.`DebitorID`=`system_debitor_domain`.`DebitorID` AND `system_debitor_domain`.`DomainStatus`='Active' AND (ISNULL(`system_debitor_domain`.`DomainExpire`) OR DATEDIFF(`system_debitor_domain`.`DomainExpire`,CURRENT_DATE()) <=60) INNER JOIN `system_product_domain` ON `system_product_domain`.`DomainTLD`=SUBSTRING(`system_debitor_domain`.`DomainName`, LOCATE('.',`system_debitor_domain`.`DomainName`)) AND FIND_IN_SET((IF(ISNULL(`DomainExpire`),IF(`DomainUpdate`>`DomainCreate`,'Move','Create'),'Renew')),`system_product_domain`.`ProductType`) INNER JOIN `system_product` ON `system_product`.`ProductID`=`system_product_domain`.`ProductID`; START TRANSACTION; OPEN tempCur; read_loop: LOOP FETCH tempCur INTO vDebitorID; IF done THEN LEAVE read_loop; END IF;
SET @p0='N14'; INSERT INTO `system_debitor_order` (`DebitorID`, `OrderType`, `OrderNr`, `OrderCreate`, `OrderPayDay`) VALUES (vDebitorID, 'Invoice', NULL, CURRENT_DATE(), `MakeDay`(@p0)); SET @orderId = LAST_INSERT_ID();
OPEN templineCur; templine_loop: LOOP FETCH templineCur INTO vLineType, vLineNr, vLineText, vLinePrice, vLineCount, vLineCountText; IF done THEN LEAVE templine_loop; END IF; INSERT INTO `system_debitor_orderline` (`orderid`, `orderlinetype`, `orderlinenr`, `orderlinetext`, `orderlineprice`, `orderlinecount`, `orderlinecounttext`) VALUES (@orderId, vLineType, vLineNr, vLineText, vLinePrice, vLineCount, vLineCountText); END LOOP; CLOSE templineCur; END LOOP;
CLOSE tempCur; COMMIT; TRUNCATE temp_orderline; END
dog uden det virker. det jeg kan se der focker op er når den har oprette orderline stopper den og gå ikke tilbage og checker ny debitoer..
Prøv at få begge dine cursors til at være helt inde i transaktionen - altså START helt i toppen og COMMIT helt i bunden (som Arne skrev).
Jeg aner ikke om det gør nogen forskel.
Hvad med din "done"-variabel. Starter som 0, sættes til 1 hvis en af dine to FETCH fejler. Skal du ikke resette den? (Og skal vi ikke tydeliggøre det med 1 og 0)
jeg har prøve at start lidt forfra BEGIN DECLARE done INT DEFAULT 0; DECLARE vDebitorID INT; DECLARE vLineType ENUM('Line', 'Text'); DECLARE vLineNr VARCHAR(15); DECLARE vLineText VARCHAR(250); DECLARE vLinePrice DECIMAL(12,2); DECLARE vLineCount INT; DECLARE vLineCountText VARCHAR(20); DECLARE DebitorCur CURSOR FOR SELECT DISTINCT DebitorID FROM temp_orderline; DECLARE OrderlineCur CURSOR FOR SELECT AutoorderType,AutoorderNr,AutoorderText,AutoorderPrice,AutoorderCount,AutoorderCountText FROM temp_orderline WHERE DebitorID=vDebitorID; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; CREATE TEMPORARY TABLE temp_orderline ( `DebitorID` int(11) NOT NULL, `AutoorderType` enum('Line','Text') NOT NULL, `AutoorderNr` varchar(15) NOT NULL, `AutoorderText` varchar(250) NOT NULL, `AutoorderPrice` decimal(12,2) NOT NULL, `AutoorderCount` int(10) NOT NULL, `AutoorderCountText` varchar(20) NOT NULL ); INSERT INTO `temp_orderline` (`DebitorID`, `AutoorderType`, `AutoorderNr`, `AutoorderText`, `AutoorderPrice`, `AutoorderCount`, `AutoorderCountText`) SELECT `system_debitor`.`DebitorID` AS DebitorID,'Line' AS AutoorderType,`system_product`.`ProductNr` AS AutoorderNr,REPLACE(REPLACE(REPLACE(`system_product`.`ProductText`,'{{domainname}}',`system_debitor_domain`.`DomainName`),'{{periodefrom}}',DATE_FORMAT(ifnull(`system_debitor_domain`.`DomainExpire`,`system_debitor_domain`.`DomainCreate`),'%d.%m.%Y')),'{{periodeto}}',DATE_FORMAT(ADDDATE(ifnull(`system_debitor_domain`.`DomainExpire`,`system_debitor_domain`.`DomainCreate`), INTERVAL `system_debitor_domain`.`DomainPeriode`*365 DAY),'%d.%m.%Y')) as AutoorderText,`system_product`.`ProductPrice` AS AutoorderPrice,`system_debitor_domain`.`DomainPeriode` AS AutoorderCount,`system_product`.`ProductEnhed` AS AutoorderCountText FROM `system_debitor_domain` INNER JOIN `system_debitor` ON `system_debitor`.`DebitorID`=`system_debitor_domain`.`DebitorID` AND `system_debitor_domain`.`DomainStatus`='Active' AND (ISNULL(`system_debitor_domain`.`DomainExpire`) OR DATEDIFF(`system_debitor_domain`.`DomainExpire`,CURRENT_DATE()) <=60) INNER JOIN `system_product_domain` ON `system_product_domain`.`DomainTLD`=SUBSTRING(`system_debitor_domain`.`DomainName`, LOCATE('.',`system_debitor_domain`.`DomainName`)) AND FIND_IN_SET((IF(ISNULL(`DomainExpire`),IF(`DomainUpdate`>`DomainCreate`,'Move','Create'),'Renew')),`system_product_domain`.`ProductType`) INNER JOIN `system_product` ON `system_product`.`ProductID`=`system_product_domain`.`ProductID` ORDER BY DebitorID; START TRANSACTION; OPEN DebitorCur;
Lopp alle DebitorCur - loop alle OrderlineCur der passer til DebitorCur
CLOSE DebitorCur; COMMIT; SELECT * FROM `temp_orderline`; TRUNCATE temp_orderline; END
Godt det lykkedes. Du må gerne ved lejlighed afprøve om du behøver at have een transaktion rundt om det hele, eller du kan lave en for hver faktura - uden at dine cursors bliver forvirrede.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.