devotionMedlem sedan jan. 20013 582 inlägg Hej på er! :)
Jag har en liten fundering.... ;)
Jag skulle vilja göra ett script som slår samman dubletter av artiklar i en databastabell.
Dvs finns en artikel med samma id på 2 ställen med olika antal ska en ny post skapas med det summerade antalet från de två ursprungsposterna. De två ursprungsposterna skall raderas.
Jag bifogar en bild på hur det ser ut i databasen innan en sammanslagning.
Resultatet skall bli som i den andra bilden...
Kan väl tillägga att jag använder SQL-server och att scriptet ska köras på "hela tabellen" schemalagt.
Mvh
Henrik
LarsGMedlem sedan dec. 200012 464 inlägg --
-- aggregera
--
update tab as q
set antal = (select sum(antal)
from tab
where tab.artikelid = q.artikelid)
where artikelid in
(select artikelid
from tab
group by artikelid
having count(*) > 1)
--
-- ta bort duplikat
--
delete from tab
where id not in
(select max(id)
from tab as q
where tab.artikelid = q.artikelid)
Flyttas från ASP
emissionMedlem sedan dec. 19996 721 inlägg ...och en sådan dubbelfråga vill du köra atomiskt, dvs. antingen körs ingen eller så körs båda (duktigt korrupt data blir resultatet annars). Med andra ord bör du kapsla in frågan i en transaktion.
devotionMedlem sedan jan. 20013 582 inlägg Hej!
Det ser ju fint ut.. :)
Jag försökte dock att ändra till mina tabellnamn och kolumner och kanske gjort fel...
update tblMaterial as q
set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.Id = q.Id)
where Id in
(select Id
from tblMaterial
group by Id
having count(*) > 1)
Ger
Msg 156, Level 15, State 1, Line 1
Felaktig syntax nära nyckelordet 'as'.
Msg 156, Level 15, State 1, Line 5
Felaktig syntax nära nyckelordet 'where'.
Mvh
Henrik
Peter SMedlem sedan dec. 20025 483 inlägg Testa
update tblMaterial
set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.Id = q.Id)
from tblMaterial as q
where Id in
(select Id
from tblMaterial
group by Id
having count(*) > 1)
emissionMedlem sedan dec. 19996 721 inlägg update q set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.ArtNr = q.ArtNr)
from tblMaterial as q
where ArtNr in
(select ArtNr
from tblMaterial
group by ArtNr
having count(*) > 1)
Det är ArtNr som kopplar ihop..
devotionMedlem sedan jan. 20013 582 inlägg
emission skrev:
update q set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.ArtNr = q.ArtNr)
from tblMaterial as q
where ArtNr in
(select ArtNr
from tblMaterial
group by ArtNr
having count(*) > 1)
Det är ArtNr som kopplar ihop..
Ja, självklart.... :r
Där satt den.... iaf den första delen... :)
Mvh
Henrik
emissionMedlem sedan dec. 19996 721 inlägg Andra delen
delete from tblMaterial
where id not in
(select max(id)
from tblMaterialas q
where tblMaterial.ArtNr= q.ArtNr)
devotionMedlem sedan jan. 20013 582 inlägg Då blir det så här om allt slås samman:
update q set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.ArtNr = q.ArtNr)
from tblMaterial as q
where ArtNr in
(select ArtNr
from tblMaterial
group by ArtNr
having count(*) > 1)
delete from tblMaterial
where id not in
(select max(id)
from tblMaterial as q
where tblMaterial.ArtNr= q.ArtNr)
Tack LarsG, emission och Peter S :birp
Mvh
Henrik
emissionMedlem sedan dec. 19996 721 inlägg ..och glöm inte transaktionen.
devotionMedlem sedan jan. 20013 582 inlägg
emission skrev:
..och glöm inte transaktionen.
Det där får du nog förklara.. :(
EDIT!
Hade missat ett inlägg ovan...
Jag har aldrig jobbat med transaktioner, så du får gärna förklara/berätta hur jag ska göra...
Tänkte dock att en sådan dubbelfråga kan skapa problem...
Mvh
Henrik
emissionMedlem sedan dec. 19996 721 inlägg Jo, som jag skrev tidigare.
"en sådan dubbelfråga vill du köra atomiskt, dvs. antingen körs ingen eller så körs båda (duktigt korrupt data blir resultatet annars). Med andra ord bör du kapsla in frågan i en transaktion."
Om fråga 1 lyckas och fråga 2 misslyckas så kommer du att få en tråkig helg.
BEGIN TRAN
--Gör hemska saker i databasen
IF (@@ERROR<>0)
BEGIN
--Något gick visst snett. Jag ångrar alltihop.
ROLLBACK TRAN
END
ELSE
BEGIN
--Wehee! Det gick ju som smort. Jag ser till att ändringarna utförs.
COMMIT TRAN
END
devotionMedlem sedan jan. 20013 582 inlägg Så här?
BEGIN TRAN
update q set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.ArtNr = q.ArtNr)
from tblMaterial as q
where ArtNr in
(select ArtNr
from tblMaterial
group by ArtNr
having count(*) > 1)
delete from tblMaterial
where id not in
(select max(id)
from tblMaterial as q
where tblMaterial.ArtNr= q.ArtNr)
IF (@@ERROR<>0)
BEGIN
ROLLBACK TRAN
END
ELSE
BEGIN
COMMIT TRAN
END
Mvh
Henrik
emissionMedlem sedan dec. 19996 721 inlägg Helt rätt tänkt Henrik! Tyvärr inte rätt (inte konstigt med min slappa beskrivning)
Saken är den att @@ERROR nollställs vid varje fråga så man måste kontrollera värdet direkt efter varje fråga, eller mellanlagra den i en variabel.
Ex:
DECLARE @updaterr int, @deleteerr int
BEGIN TRAN
update q set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.ArtNr = q.ArtNr)
from tblMaterial as q
where ArtNr in
(select ArtNr
from tblMaterial
group by ArtNr
having count(*) > 1)
SELECT @updaterr=@@ERROR
--Här skulle man kunna hoppa över resten, och direkt köra en rollback, eftersom nästa fråga ändå inte ska köras.
delete from tblMaterial
where id not in
(select max(id)
from tblMaterial as q
where tblMaterial.ArtNr= q.ArtNr)
SELECT @deleteerr=@@ERROR
IF (@updaterr<>0 or @deleteerr<>0)
BEGIN
ROLLBACK TRAN
END
ELSE
BEGIN
COMMIT TRAN
END
Kom precis på att du väl kör SQL Server 2005? Då finns en efterlängtad TRY-CATCH-metod att ta till också, men den har jag knappt provat så jag överlåter informationsspridningen till Google...
devotionMedlem sedan jan. 20013 582 inlägg :)
God morgon!
Hehe... Detta är lite överkurs för mig... Men, men, man får väl lära sig något nytt!
Då ska det se ut så här:
DECLARE @updaterr int, @deleteerr int
BEGIN TRAN
update q set Amount = (select sum(Amount)
from tblMaterial
where tblMaterial.ArtNr = q.ArtNr)
from tblMaterial as q
where ArtNr in
(select ArtNr
from tblMaterial
group by ArtNr
having count(*) > 1)
SELECT @updaterr=@@ERROR
delete from tblMaterial
where id not in
(select max(id)
from tblMaterial as q
where tblMaterial.ArtNr= q.ArtNr)
SELECT @deleteerr=@@ERROR
IF (@updaterr<>0 or @deleteerr<>0)
BEGIN
ROLLBACK TRAN
END
ELSE
BEGIN
COMMIT TRAN
END
Är detta säkert?
Min tanke är at schemalägga detta för att just plocka bort dubletter 1 gång per dygn... (städa upp efter användarna... ;) )
Angående den andra metoden, ska jag leta lite! :)
Mvh
Henrik
devotionMedlem sedan jan. 20013 582 inlägg Hej igen! :)
Kan man kombinera det hela med att "logga" det som utförs?
Kan man köra en transaktion i en asp-sida?
Är det säkert att köra transaktionen?
Mvh
Henrik
emissionMedlem sedan dec. 19996 721 inlägg Du kan definitivt logga det som utförs. Skriv in rad i en tabell, helt enkelt. Gör det dock inte inne i samma transaktion, eftersom en rollback skulle ta bort loggningen också.
Ja, du kan köra en transaktion på en asp-sida. Antingen genom att skriva som ovan, med BEGIN TRANS etc., eller genom att köra
on error resume next
objConn.BeginTrans
objConn.Execute("INSERT ......
if err.Number<>0 or If objConn.errors.count>0 then
objConn.RollbackTrans
else
objConn.CommitTrans
end if
on error goto 0
Säkert? Hur menar du?
devotionMedlem sedan jan. 20013 582 inlägg Hej! :)
Med säkert menar jag, att jag inte får korrupt data... Dvs vågar jag köra transaktionen? :)
Hur skrivar man in raden i tabellen då? Eller hur jag skriver vet jag, men vad ska jag skriva? :)
Mvh
Henrik
emissionMedlem sedan dec. 19996 721 inlägg
devotion skrev:
Hej! :)
Med säkert menar jag, att jag inte får korrupt data... Dvs vågar jag köra transaktionen? :)
Jupp.
devotion skrev:
Hur skrivar man in raden i tabellen då? Eller hur jag skriver vet jag, men vad ska jag skriva? :)
Det får du banne mig hitta på själv :)