webForumDet fria alternativet

Kopiera data mellan tabeller med olika struktur

Databaser & SQL

11 svar · 341 visningar · startad av jepsO

Medlem sedan mars 2001484 inlägg
Frågan#1

Jag har i ett databasprojekt sökt igenom en webbplats och fran denna hämtat information som nu är lagrad i en tabell data med följade struktur:

-------------------------------------
| table | id | type  | value        |
-------------------------------------
| dvd   | 01 | title | Finding Nemo |
| dvd   | 01 | price | 9.99         |
| dvd   | 01 | genre | Disney       |
| dvd   | 02 | title | Gladiator    |
| dvd   | 02 | price | 10.99        |
etc                                 |
-------------------------------------

Vad som ska ske är att innehallet i data ska föras över till den tabell som anges i fältet table. I mitt fall är det dock bara maltabellen "dvd" som är aktuell. En förenklad struktur av dvd är som följer:

| id | title | price | genre |

data ska alltsa föras över via följande tva rader:

| 01 | Finding Nemo | 9.99 | Disney |
| 02 | Gladiator | 9.99 | NULL |
(Gladiator har alltsa ingen angiven genre.)

Nagra tips pa hur detta görs enklast? Det är framför allt den inledande SQL-fragan jag funderar pa; är det smartast att göra en simpel SELECT DISTINCT(id) och sedan loopa fram information för varje film i ett Java-program, eller har ni nagra bättre förslag (GROUP BY kanske)?

Medlem sedan apr. 2004778 inlägg
#2

Antingen hämtar du all data och loopar igenom i ett program och gör en INSERT för varje rad, som du själv föreslår.
Eller så gör du loopningen i SPn med cursors.

Alternativ tre skulle vara att göra en INSERT och för varje värde som ska in gör man en SELECT på id. Men jag har ingen testad kod för detta just nu.

Medlem sedan mars 2001484 inlägg
#3

PDahlen skrev:

Eller så gör du loopningen i SPn med cursors.

Oj, här snackas det nya grejor :). Vad innebär en "loopning i SPn med cursors"?

För att spinna vidare pa mitt egna förslag kan jag precisera vari min fraga ligger:

SELECT DISTINCT(id) FROM data

loop
INSERT INTO dvd (id, title, price, genre) VALUES [b][red]vad kommer här?[/red][/b]
end loop

Kan jag (1) lägga flera SELECT-satser i INSERT-satsen, eller (2) maste jag först plocka ut önskade värden via separata SELECT-satser? Nagot slags exempel ($ indikerar variabel):

1.
INSERT INTO dvd (id, title, price, genre) VALUES ($id, (SELECT title FROM data WHERE id = $id), (SELECT price FROM data WHERE id = $id) ...)

2.
$title = SELECT title FROM data WHERE id = $id
...
INSERT INTO dvd (...) VALUES ($id, $title, ...)
Medlem sedan mars 20032 667 inlägg
#4

jepsO skrev:

Nagra tips pa hur detta görs enklast? Det är framför allt den inledande SQL-fragan jag funderar pa; är det smartast att göra en simpel SELECT DISTINCT(id) och sedan loopa fram information för varje film i ett Java-program, eller har ni nagra bättre förslag (GROUP BY kanske)?

Jag hajar inte riktigt vad du vill göra. Du vill alltså hämta unika poster (id) från en tabell och lagra dem i en ny tabell med ett annat utseende? Du behöver också hämta fler kolumner från tabellen än id? Vilken databashanterare använder du?

PS.
Distinct är ingen funktion och ska skrivas "distinct id", utan paranterser.

Medlem sedan dec. 200012 464 inlägg
#5
insert into dvd 
select distinct id, 
  (select value from data where type = 'title' and id = d.id),
  (select cast(value as decimal(10,2)) from data where type = 'price' and id = d.id),
  (select value from data where type = 'genre' and id = d.id)
from data as d

Du kanske måste lägga till någon ytterligare cast för t.ex. id.

Medlem sedan mars 2001484 inlägg
#6

K@llen: Precis. Later förmodligen ganska onödigt, men själva överföringen av data mellan de tva tabellerna är en del av projektet. Tack för papekandet om distinct.

LarsG: Det där ser väldigt lovande ut. Ska testas bums i morgon :).

Medlem sedan mars 2001484 inlägg
#7

Hmm, testade LarsG:s kod men fick följande felmeddelande:

Error Message:  SubQuery result is not a single scalar value.
Error SQLState: ZG011
Error Code:     25011

Min tolkning av felet är att det skapas ett "result set" i stället för ett enskilt värde nagonstans, men varför? Kan det vara pa grund av dubletter?

Använder Pointbase som DBMS, om det nu kan ha nagon betydelse.

Medlem sedan dec. 200012 464 inlägg
#8

Kan det vara pa grund av dubletter?

Jo.

Det var lite oklart om det fanns med data för andra tabeller än dvd. I så fall kan du lägga på det villkoret.

insert into dvd 
select distinct id, 
  (select value from data where type = 'title' and id = d.id
  and table = 'dvd'),
  (select cast(value as decimal(10,2)) from data where type = 'price' and id = d.id and table = 'dvd'),
  (select value from data where type = 'genre' and id = d.id and table = 'dvd')
from data as d
where table = 'dvd'

(table är inget bra kolumnnamn.)

Om du fortfarande får flera poster så kanske det hjälper med att lägga till distinct i subselect.

select distinct value

Om det fortfarande inte hjälper så har du nog lite problem med ditt indata efetrsom det finns motstridiga uppgifter.

Medlem sedan mars 2001484 inlägg
#9

Grr, far det fortfarande inte att fungera. För att lättare kunna se felet gjorde jag en tabell Data_Test med följande struktur och innehall (de horisontala strecken är bara där för att tydliggöra innehallet):

--------------------------------
| id  | type   | value         |
--------------------------------
| 111 | title  | First title   |
| 111 | genre  | First genre   |
| 111 | seller | First seller  |
--------------------------------
| 222 | title  | Second title  |
| 222 | genre  | Second genre  |
| 222 | seller | Second seller |
--------------------------------
| 333 | title  | Third title   |
| 333 | genre  | Third genre   |
| 333 | seller | Third seller  |
--------------------------------

Mitt mal är nu att med följande kod lyckas skapa tre rader i tabellen Dvd:

insert into dvd 
select distinct id, 
  (select value from data_test where type = 'title' and id = d.id),
  (select value from data_test where type = 'genre' and id = d.id),
  (select value from data_test where type = 'seller' and id = d.id)
from data_test as d;

Glad i hagen trodde jag att nu MASTE det vara rätt. Men ... Resultatet blir tre identiska rader för varje ID :(. Att lägga in DISTINCT även för title, genre och seller gav inget, och verkar i detta fall hellre inte sa logiskt.

Kan det vara Pointbase, min DBMS, som inte klarar av den här typen av SQL-fragor?

Medlem sedan dec. 200012 464 inlägg
#10

För att kontrollera om du har flera värden för samma id och type

select id,type,count(*)
from data
where table = 'dvd'
group by id,type
having count(*) > 1
Medlem sedan mars 2001484 inlägg
#11

Den koden var mycket användbar!

Utan dubletter aterkommer jag dock till problemet som beskrivs ovan, da jag använder Data_Test -- trots DISTINCT-attributet försöker Pointbase skapa en rad i Dvd för varje attribut som matchar aktuellt id.

Output för Data_Test ovan blir alltsa

-----------------------------------------------------
| id  | title        | genre        | seller        |
-----------------------------------------------------
| 111 | First title  | First genre  | First seller  |
| 111 | First title  | First genre  | First seller  |
| 111 | First title  | First genre  | First seller  |
-----------------------------------------------------
| 222 | Second title | Second genre | Second seller |
| 222 | Second title | Second genre | Second seller |
| 222 | Second title | Second genre | Second seller |
-----------------------------------------------------
| 333 | Third title  | Third genre  | Third seller  |
| 333 | Third title  | Third genre  | Third seller  |
| 333 | Third title  | Third genre  | Third seller  |
-----------------------------------------------------

Den outputen utan dublettrader och allt skulle vara frid och fröjd ...

Medlem sedan mars 2001484 inlägg
#12

Lösningen var ju inte sa svar trots allt:

CREATE VIEW DvdView AS
select distinct id, 
  (select value from data_test where type = 'title' and id = d.id),
  (select value from data_test where type = 'genre' and id = d.id),
  (select value from data_test where type = 'seller' and id = d.id)
from data_test as d;

INSERT INTO Dvd
select distinct * from DvdView;

Behövdes bara lite tid för eftertanke :). Tack LarsG för hjälpen!

282 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
132 ms — deklarationer (db)
0 ms — hämta statistik (cache)
147 ms — hämta tråd, inlägg och bilagor (db)
130 ms — ändringar (db)