FAQ |
Kalender |
![]() |
#1 | ||
|
|||
Medlem
|
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)) Kod:
INSERT INTO person VALUES (NULL, 'Antonio Paz', NULL); 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! |
||
![]() |
![]() |
![]() |
#2 | |||
|
||||
Har WN som tidsfördriv
|
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 |
|||
![]() |
![]() |
![]() |
#3 | ||
|
|||
Medlem
|
Citat:
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 Kod:
INSERT INTO person VALUES (NULL, name, NULL); 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 |
||
![]() |
![]() |
![]() |
#4 | |||
|
||||
Har WN som tidsfördriv
|
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 // Den där triggern triggas varje gång du kör en INSERT på den tabellen i all fall. |
|||
![]() |
![]() |
![]() |
#5 | ||
|
|||
Supermoderator
|
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:
__________________
Jonny Zetterström se.linkedin.com/in/jonnyz | bjz.se | sajthotellet.com | kalsongkungen.se | zretail.se | zetterstromnetworks.se | webbhotellsguide.se | ekonominyheter24.se | nyamobiltelefoner.se | gapskratt.se | antivirusguiden.se | jonny.nu |
||
![]() |
![]() |
![]() |
#6 | ||
|
|||
Klarade millennium-buggen
|
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)) 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$$ Senast redigerad av Conny Westh den 2010-12-18 klockan 00:21 |
||
![]() |
![]() |
![]() |
#7 | |||
|
||||
Medlem
|
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; 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; 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; Kod:
CALL insertName('Nisse Hult'); CALL insertName('Anders Borg'); CALL insertName('Barak Obama'); Kod:
CALL insertName('Nisse Hult'); Var det så du villa ha det? · Senast redigerad av aelander den 2010-12-18 klockan 03:55 |
|||
![]() |
![]() |
![]() |
#8 | ||
|
|||
Klarade millennium-buggen
|
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 |
||
![]() |
![]() |
![]() |
#9 | |||
|
||||
Medlem
|
Citat:
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. |
|||
![]() |
![]() |
![]() |
#10 | ||
|
|||
Klarade millennium-buggen
|
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 |
||
![]() |
![]() |
Svara |
|
|