Avatar billede SommerFyr Seniormester
13. august 2024 - 15:08 Der 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`;
   
END
Avatar billede arne_v Ekspert
13. august 2024 - 16:08 #1
Hvad er baggrunden for at lave det i ren SQL fremfor i et programmerings-sprog C#/VB.NET/Java/PHP/Python/whatever?
Avatar billede SommerFyr Seniormester
13. august 2024 - 16:17 #2
Hej Arne..

Tja fik af vide det var nemmer. og de ander løsninger jeg har prøve på har drille meget mere.

jeg har side og prøve og prøve og lige nu tor jeg at jeg ved hvor den fejler. dog er jeg usikker på hvordan jeg løser det.

jeg loop to gang og siste loop fejler.

Hvis jeg skulle lave det i anden ville det nok blive nåde node.js eller php.. men så er det helt tilbage til start..
Avatar billede erikjacobsen Ekspert
13. august 2024 - 18:55 #3
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.
Avatar billede arne_v Ekspert
13. august 2024 - 19:32 #4
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.
Avatar billede erikjacobsen Ekspert
13. august 2024 - 19:36 #5
Hov, ja, START TRANSACTION skal også rykkes længere op ;)
Avatar billede SommerFyr Seniormester
13. august 2024 - 20:49 #6
jeg har prøve lidt

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..

ved ikke om jeg skal to done eller nåde !!!
Avatar billede erikjacobsen Ekspert
13. august 2024 - 21:00 #7
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)

  IF done=1 THEN
    done=0
    ...
Avatar billede SommerFyr Seniormester
13. august 2024 - 21:09 #8
Hej erikjacobsen

Jeg er ikke lige med på hvad du mender !!!
Avatar billede erikjacobsen Ekspert
13. august 2024 - 21:17 #9
Hvis du een gang har fået sat done til 1, bliver den ved med at være det. Det kan forklare opførslen. Derfor sæt den til 0 hver gang.
Avatar billede erikjacobsen Ekspert
13. august 2024 - 21:18 #10
Alterntiv: sæt den til 0 lige før dine FETCH. Det gør det nemmere at læse.
Avatar billede erikjacobsen Ekspert
13. august 2024 - 21:22 #11
Øh, hov - skal du ikke også sige ITERATE?

"You use the ITERATE statement to execute the loop again."
Avatar billede SommerFyr Seniormester
13. august 2024 - 21:41 #12
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

håber der er en der kan give det et bud..
Avatar billede erikjacobsen Ekspert
13. august 2024 - 21:48 #13
Nej, man skal ikke bruge ITERATE, med mindre man vil løbe igennem en gang til inden man når END LOOP. Det giver jo go' mening.

Har du prøvet forslaget med at sætte done til 0?
Avatar billede SommerFyr Seniormester
13. august 2024 - 21:52 #14
Hej Erikjacobsen.. jeg er overhove ikke med på hvad du mender..
Avatar billede erikjacobsen Ekspert
13. august 2024 - 21:54 #15
Indlæg #9 og #10 - hvad forstår du ikke?
Avatar billede SommerFyr Seniormester
13. august 2024 - 21:56 #16
Begge..
Avatar billede SommerFyr Seniormester
13. august 2024 - 22:28 #17
Så tro jeg at jeg fandt fejlen.. nu laver den faktura til 10700 kunder og ikke bare en..
SET done = 0;
Avatar billede erikjacobsen Ekspert
14. august 2024 - 17:24 #18
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.
Avatar billede SommerFyr Seniormester
15. august 2024 - 17:53 #19
Hej igen..

Det ser ud til at det bare køre der ud af. jeg flytte START TRANSACTION; til før OPEN DebitorCur; og satte SET done = 1;
Avatar billede SommerFyr Seniormester
15. august 2024 - 17:53 #20
jeg har også prøve uden START TRANSACTION; der virker det også..
Avatar billede SommerFyr Seniormester
15. august 2024 - 17:54 #21
Takker for hjælpen..
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester



IT-JOB

Arbejdernes Landsbank

Fullstack-udvikler med fokus på AI

Danske Andelskassers Bank A/S

IT-konsulent

MAN Energy Solutions

Full Stack Developer