Kom ihåg mig?
Home Menu

Menu


Hjälp med att skapa MySQL procedure

Ämnesverktyg Visningsalternativ
Oläst 2010-12-16, 22:01 #1
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
Standard Hjälp med att skapa MySQL procedure

Hej!

Jag skulle vilja be er om lite hjälp. Jag skulle nämligen behöva hjälpa med att skriva en procedure i MySQL som gör följande:

Det jag vill att proceduren gör är att den ska lägga till information i en annan tabell och referera via en tabel.

Exempelvis om jag har en tabell kallad personer och en annan namn.

Kod:
CREATE TABLE person(
    id INT NOT NULL AUTO_INCREMENT,
    name int(11) NOT NULL,
    age int(11) default NULL, 
    REFERENCES name(id),
    PRIMARY KEY (id))
Kod:
CREATE TABLE name(
    id INT NOT NULL AUTO_INCREMENT,
    name varchar(255) NOT NULL,
    PRIMARY KEY (id))
Det som jag vill att denna procedure ska göra är att när jag gör följande sql sats:

Kod:
INSERT INTO person VALUES (NULL, 'Antonio Paz', NULL);
Så ska den lägga till Antinio Paz i nametabellen om den inte redan finns och sedan skapa en referns från name tabellen via dess id som placeras i persontabellens name.
Jag har försökt hitta information om hur man gör detta själv men inte riktigt lyckas.

Så om någon skulle vilja hjälpa mig med att skriva denna lilla procedure vore han guld värd!
mojitoo är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-16, 22:46 #2
pelmereds avatar
pelmered pelmered är inte uppkopplad
Har WN som tidsfördriv
 
Reg.datum: May 2010
Inlägg: 1 342
pelmered pelmered är inte uppkopplad
Har WN som tidsfördriv
pelmereds avatar
 
Reg.datum: May 2010
Inlägg: 1 342
Det du ska göra är väl en trigger då?
Men jag vet inte hur man gör för att få ut namnet ur SQL-satsen i en trigger.

Du kanske måste göra en procedur som du anropar direkt. Då blir det någon sånt här:

Kod:
CREATE PROCEDURE insertName(IN name CHAR(100);)
BEGIN
	INSERT INTO person VALUES (NULL, name, NULL);
	INSERT INTO name VALUES (NULL, name);
END
pelmered är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-16, 23:04 #3
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
Citat:
Ursprungligen postat av ITisGood.se Visa inlägg
Det du ska göra är väl en trigger då?
Men jag vet inte hur man gör för att få ut namnet ur SQL-satsen i en trigger.

Du kanske måste göra en procedur som du anropar direkt. Då blir det någon sånt här:

Kod:
CREATE PROCEDURE insertName(IN name CHAR(100);)
BEGIN
	INSERT INTO person VALUES (NULL, name, NULL);
	INSERT INTO name VALUES (NULL, name);
END
Det är mycket möjligt att det är en trigger jag behöver göra O.o
Jag är som sagt ny på det området och försöker lära mig.

Men jag antar att min idé kommer att fungera sedan? Så att jag slipper skriva exempelvis detta varje gång:
Kod:
CREATE PROCEDURE insertName(IN name CHAR(100);)
BEGIN
	INSERT INTO person VALUES (NULL, name, NULL);
	INSERT INTO name VALUES (NULL, name);
END
Och istället bara kan skriva:
Kod:
INSERT INTO person VALUES (NULL, name, NULL);
Det är iaf den funktionaliteten som jag vill komma åt men som jag vet inte riktigt hur man gör.

edit:
Fick även följande fel när jag testade din kod:
Kod:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1

Senast redigerad av mojitoo den 2010-12-16 klockan 23:08
mojitoo är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-17, 01:01 #4
pelmereds avatar
pelmered pelmered är inte uppkopplad
Har WN som tidsfördriv
 
Reg.datum: May 2010
Inlägg: 1 342
pelmered pelmered är inte uppkopplad
Har WN som tidsfördriv
pelmereds avatar
 
Reg.datum: May 2010
Inlägg: 1 342
Oj, det semikolonet på första raden ska inte vara där.

En trigger gör man såhär föresten:

Kod:
CREATE TRIGGER `databas`.`onInsertInsertName` BEFORE INSERT ON `databas`.`person`
 FOR EACH ROW BEGIN
       
       INSERT INTO name VALUES (NULL, 'Antonio Paz');
       
    END
//
Problemet är att jag inte vet om man kan få ut namnet ur den ursprungliga queryn och stoppa in i query i triggern...
Den där triggern triggas varje gång du kör en INSERT på den tabellen i all fall.
pelmered är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-17, 09:06 #5
jonny jonny är inte uppkopplad
Supermoderator
 
Reg.datum: Sep 2003
Inlägg: 6 941
jonny jonny är inte uppkopplad
Supermoderator
 
Reg.datum: Sep 2003
Inlägg: 6 941
Nu gillar jag inte triggers alls - jag vill inte ha logik i databasen - och jag har mest använt Oracle på sistone. Men du bör kunna komma åt värdet du försöker mata in utan problem.

Lite googlande gav:
Citat:
You can refer to columns in the subject table (the table associated with the trigger) by using the aliases OLD and NEW. OLD.col_name refers to a column of an existing row before it is updated or deleted. NEW.col_name refers to the column of a new row to be inserted or an existing row after it is updated.
http://dev.mysql.com/doc/refman/5.0/...e-trigger.html
jonny är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-17, 23:42 #6
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Det ska inte vara något kommatecken före REFERENCES:

Kod:
CREATE TABLE person(
    id INT NOT NULL AUTO_INCREMENT,
    name int(11) NOT NULL,
    age int(11) default NULL REFERENCES name(id),
    PRIMARY KEY (id))
Sen såg jag att du glömt att göra kolumnen "name" unik i tabellen "Name" vilket motverkar syftet med den tabellen. Sätt unikt index på den kolumnen.

Utöver det skulle jag rekommendera att inte lagra värde på age utan lagra YearOfBirth i stället och sedan räkna ut ålder utifrån dagens datum. Age är inget stabilt värde utan det förändras med automatik när klockar går. Det är för det mesta bättre att lagra ett stabilt värde och sedan räkna ut de instabila värdena. Detta sagt utan att veta exakt hur din databas kommer att användas.


Kod:
delimiter $$

CREATE TABLE `name` 
(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1$$


Kod:
delimiter $$

CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
Jag använder version 5.1.53 har inte hunnit uppdatera till 5.5.8 ännu men jag har laddat ner den i alla fall.

Senast redigerad av Conny Westh den 2010-12-18 klockan 00:21
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-18, 03:52 #7
aelanders avatar
aelander aelander är inte uppkopplad
Medlem
 
Reg.datum: Dec 2004
Inlägg: 146
aelander aelander är inte uppkopplad
Medlem
aelanders avatar
 
Reg.datum: Dec 2004
Inlägg: 146
Tycker inte om när tabeller och fält har samma namn. Det blir förvillande (det är väl åldern), men jag gör ett försök ändå.

Skapa tabellerna:
Kod:
create table Person (
  Id int unsigned not null auto_increment primary key,
  Name int unsigned not null,
  Age tinyint unsigned default null
) engine=innodb;

Kod:
create table Name (
  Id int unsigned not null auto_increment primary key,
  Name varchar(255) not null ,
  unique key Name_unique (Name)
) engine = innodb default charset=latin1;
Skapa proceduren.
Kod:
delimiter //

create procedure insertName(Namn tinytext)
begin
  declare chk int default 0;
  select count(*) from Name where Name = Namn into chk;
  if chk = 0 then
    insert into Name (Name) values (Namn);
    insert into Person (Name) values (last_insert_id());
  end if;
end
//

delimiter ;

Lite kommentarer till proceduren.

Kollar om Namn finns i tabell Name, dvs räknar hur många Namn det finns i tabellen.
Kan ge resultat 0 eller 1.
Kod:
select count(*) from Name where Name = Namn into chk;
Om INTE så lägg dit den.
Ta Id:et på posten stoppa in i tabellen Person
Kod:
  if chk = 0 then
    insert into Name (Name) values (Namn);
    insert into Person (Name) values (last_insert_id());
  end if;
Anropa med
Kod:
CALL insertName('Nisse Hult');
CALL insertName('Anders Borg');
CALL insertName('Barak Obama');
Prova att anropa igen med och upptäck att ingenting händer.
Kod:
CALL insertName('Nisse Hult');

Var det så du villa ha det?





·

Senast redigerad av aelander den 2010-12-18 klockan 03:55
aelander är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-18, 13:36 #8
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Jag skulle gissa att TS har för avsikt att använda tabellen Name med unika namn men att tabellen Person kan gha flera likadana referenser till namn i Namn-trabelen, det kan ju finnas en Nisse som är 23 år och en som är 35 exempelvis.

Tabellen person behöver troligen byggas ut så att man separerar för och efternamn samt att man byter age mot BirthYear samt att man har ytterligare kolumner för at särskilja de olika personerna. Men en början är att ha en Stored Procedure som ser ut så här:

Jag har också ändrat namnet på aelanders SP så namnet återspeglar vad man egentligen vill göra med SPn, dvs lägga till en person med namn och ålder. Men att namnets klartext endast ska sparas en gång för att bland annat spara utrymme.

Om du lägger in både förnamn och efternamn i kolumnen namn så kommer utrymmesbesparingen att vara obetydlig jämfört om du delar upp förnamn och efternamn i varsin kolumn.

Just i detta fall passar det inte att använda en TRIGGER.

Kod:
-- Följande tabelldefintioner har jag använt:
delimiter $$

CREATE TABLE `name` 
(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=57 DEFAULT CHARSET=latin1$$


delimiter $$

CREATE TABLE `person` 
(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1$$


Kod:
DELIMITER //
//
DROP PROCEDURE IF EXISTS addPerson;
//
delimiter //
create procedure addPerson(Namn tinytext, age int(11))
begin
  declare chk int default 0;
  select count(*) from Name where Name = Namn into chk;
  if chk = 0 then
    insert into Name (Name) values (Namn);
    insert into Person (Name, age) values (last_insert_id(), age);
  else
    -- Om tanken med proceduren är att man ska kunna lägga till alla personer i 
    -- Persontabellen oavsett om namnet finns sedan tidigare men inga dubbletter
    -- i name-tabellen så ska även denna insert-sats med, kanske bör fler villkor 
    -- byggas till för att det ska bli en vettig funktionalitet.
    insert into Person (Name, age) values ((select id from name where name=Namn), age);
  end if;
end
//

delimiter ;

Kod:
-- Uppläggning av testdata
CALL addPerson('Nisse', 23);
CALL addPerson('Anders', 34);
CALL addPerson('Barak', 36);

CALL addPerson('Nisse', 33);
CALL addPerson('Anders', 44);
CALL addPerson('Barak', 46);

CALL addPerson('Nisse', 43);
CALL addPerson('Anders', 54);
CALL addPerson('Barak', 56);
Kod:
-- Visa innehållet i tabellerna efter att man kört SPn

-- Endast 3 förekomster/tupler i Name-tabellen
select * from Name order by name; 

-- Men hela 9 förekomster/tupler i Persontabellen
SELECT    p.id, n.name, p.age  
FROM       Person p, name n 
WHERE     p.name=n.id
ORDER BY name;
Kod:
-- Här även en View så man enkelt kan presetera värden från Persontabellen genom att skriva:
-- SELECT * FROM Person_view 
-- ...i stället för en krånglig SQL-sats...
delimiter //

CREATE VIEW `person_view` AS 
select `p`.`id` AS `id`,`n`.`name` AS `name`,`p`.`age` AS `age` 
from (`person` `p` join `name` `n`) 
where (`p`.`name` = `n`.`id`) 
order by `n`.`name`

//

Senast redigerad av Conny Westh den 2010-12-20 klockan 05:54
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-18, 15:25 #9
aelanders avatar
aelander aelander är inte uppkopplad
Medlem
 
Reg.datum: Dec 2004
Inlägg: 146
aelander aelander är inte uppkopplad
Medlem
aelanders avatar
 
Reg.datum: Dec 2004
Inlägg: 146
Citat:
Ursprungligen postat av ConnyWesth Visa inlägg
Jag skulle gissa att TS har för avsikt att använda tabellen Name med unika namn men att tabellen Person kan gha flera likadana referenser till namn i Namn-tabellen, det kan ju finnas en Nisse som är 23 år och en som är 35 exempelvis.

Tabellen person behöver troligen byggas ut så att man separerar för och efternamn samt att man byter age mot BirthYear samt att man har ytterligare kolumner för at särskilja de olika personerna.
Goda synpunkter!

Jag förmodar att du menar att man ser till att man endast har exvis en Nisse, en Barak osv i tabellen.

Men man stöter ju på lite problem när man delar för- och efternamn. Tänk att man lägger till
Nisse Karlsson
Nisse Andersson
Per Karlsson

Hur gör man för att ha "äkta relationer". Blir dessa tre personer lika med tre poster i tabellen Name?

Kanske man i så fall borde ha två tabeller
FirstName
LastName
Eller det går att lösa på annat sätt?


Nästa problem är när man har dubbelnamn med blanksteg mellan namnen.
Nils Petter Sundgren
http://sv.wikipedia.org/wiki/Nils_Petter_Sundgren

Elisabeth Tarras Wahlberg
http://sv.wikipedia.org/wiki/Elisabeth_Tarras-Wahlberg
Nu skriver ju detta som Elisabeth Tarras-Wahlberg, men jag kom inte på nåt annat exempel.

Ganska omöjligt att automatisk avgöra vilket som är för- resp efternamn.
Kan ju lösas med två inmatningsfält !

som parantes:
För övrigt tycker jag att detta är en diskussion som leder saker framåt till skillnad mot
de flesta inlägg under webbhotell, se http://www.wn.se/t1045305.html
slut parantes.

Skulle vilja att mojitoo mer konkret beskrev vad som ska göras.
aelander är inte uppkopplad   Svara med citatSvara med citat
Oläst 2010-12-18, 19:41 #10
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Det här är en fråga om hur Normaliserad information TS vill hantera.

Vill man gå hela vägen (fortfarande inom 3:e normalformen) så kan man helt ta bort referensen till Name-tabellen i tabellen Person och lägga upp en relationstabell mellan Name och Person-tabellerna, och då givetvis ha separata tabeller för förnamn respektive efternamn.

En sådan relationstabell skulle kunna ha följande columner:

Tabell: PersonFirstName
PK1: Person.id as integer
PK2: FirstName.name as integer
Ordning as Integer
Tilltalsnamn as Boolean

Tabell: PersonLastName
PK1: Person.id as integer
PK2: LastName.name as integer
Ordning as Integer



Man skulle då klara att hantera Både Nils Petter Sundgren och Elisabeth Tarras Wahlberg, samt Maria Teresa Oksana Wahlberg Persson Jonsson som helt atomära (odelbara) namnreferenser.

Man skulle även kunna hantera mitt namn "Per Conny Mikael Westh" där Conny är tilltalsnamnet, vilket många system inte klarar idag. Det har hänt otaliga gånger att jag får heta Per eftersom det är det första namnet och tyvärr har många kravställare på systemet inte förstått att tilltalsnamnet kan vara vilket som helst av alla förnamnen. Min far hade dessutom två tilltalsnamn "Per-Gunnar Westh".

I exempelvis holland är det mycket vanligt med "von", "van", "van den" osv, finns en hel uppsjö av tillägg till efternamnet, ibland ska sortering INTE ske på dessa tillägg utan på det första "riktiga" efternamnet, då behöver man kunna plocka fram detta på ett enkelt sätt ur systemet.

Man kan även ha separata inmatningsfält för att det ska vara lätt att lägga upp nya förekomster/tupler. Om man väljer att ha ett inmatningsfält behöver man nog ha ett skiljetecken för att separera för och efternamnsdelarna. Men man kan även använda et inmatningsfält för alla förnamn och ett för alla efternamn, då känns det naturligare för användaren vid inmatningen och det blir ingen som missar skiljetecknet. Det blir även mer likformigt med hur många system ser ut för användaren idag, men man kan då ha en annan lösning i bakgrunden som användaren aldrig märker av.

Senast redigerad av Conny Westh den 2010-12-18 klockan 20:15
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Svara


Aktiva användare som för närvarande tittar på det här ämnet: 1 (0 medlemmar och 1 gäster)
 

Regler för att posta
Du får inte posta nya ämnen
Du får inte posta svar
Du får inte posta bifogade filer
Du får inte redigera dina inlägg

BB-kod är
Smilies är
[IMG]-kod är
HTML-kod är av

Forumhopp


Alla tider är GMT +2. Klockan är nu 09:29.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson
 
Copyright © 2017