2010-10-14 11 views
14

Mam nieznormalizowanych tabelę z kolumną zawierającą oddzielone przecinkami listę, która jest klucz obcy do innej tabeli:MySQL: Split oddzielonych przecinkami listę w wielu wierszach

+----------+-------------+ +--------------+-------+ 
| part_id | material | | material_id | name | 
+----------+-------------+ +--------------+-------+ 
|  339 | 1.2mm;1.6mm | |   1 | 1.2mm | 
|  970 | 1.6mm  | |   2 | 1.6mm | 
+----------+-------------+ +--------------+-------+ 

chcę czytać te dane w poszukiwaniu silnik, który nie oferuje żadnego języka proceduralnego.

Więc czy jest jakiś sposób aby albo dokonać dołączyć na tej kolumnie lub uruchomić zapytanie o te dane, które wstawia odpowiednie wpisy do nowej tabeli? Uzyskane dane powinny wyglądać następująco:

+---------+-------------+ 
| part_id | material_id | 
+---------+-------------+ 
|  339 |   1 | 
|  339 |   2 | 
|  970 |   2 | 
+---------+-------------+ 

mogę wymyślić rozwiązanie, jeśli DBMS obsługiwane funkcje wracające tabeli MySQL, ale najwyraźniej nie.

Odpowiedz

9

W MySQL można to osiągnąć jak poniżej

SELECT id, length FROM vehicles WHERE id IN (117, 148, 126) 

+---------------+ 
| id | length | 
+---------------+ 
| 117 | 25  | 
| 126 | 8  | 
| 148 | 10  | 
+---------------+ 

SELECT id,vehicle_ids FROM load_plan_configs WHERE load_plan_configs.id =42 

+---------------------+ 
| id | vehicle_ids | 
+---------------------+ 
| 42 | 117, 148, 126 | 
+---------------------+ 

Teraz, aby uzyskać długość oddzielonych przecinkami vehicle_ids skorzystać z poniższego zapytania

Output 

SELECT length 
FROM vehicles, load_plan_configs 
WHERE load_plan_configs.id = 42 AND FIND_IN_SET(
     vehicles.id, load_plan_configs.vehicle_ids 
) 

+---------+ 
| length | 
+---------+ 
| 25  | 
| 8  | 
| 10  | 
+---------+ 

For more info visit http://amitbrothers.blogspot.in/2014/03/mysql-split-comma-separated-list-into.html

+0

Tak pomocne, mam do czynienia z DB z danych CSV w niektórych kolumnach zbyt – lintuxvi

5

Odpowiedziałem na dwa podobne pytania w ciągu tylu dni, ale nie miałem odpowiedzi, więc myślę, że ludzie są zniechęceni przez użycie kursora, ale jak powinno to być jednorazowy proces, którego osobiście nie uważam, że to ma znaczenie.

Jak stwierdził użytkownik, MySQL nie obsługuje typów zwracanych przez tabelę, więc nie ma innej możliwości niż zapętlenie tabeli i przeanalizowanie łańcucha CSV materiału oraz wygenerowanie odpowiednich wierszy dla części i materiału.

Poniższe wpisy mogą okazać się interesujące:

split keywords for post php mysql

MySQL procedure to load data from staging table to other tables. Need to split up multivalue field in the process

Rgds

+0

Nie jestem pewien, czy możesz to zrobić bez pętli, chyba że jest ustawiona maksymalna liczba wartości, które mogą znajdować się w wartościach rozdzielanych przecinkami ... jesteś jakby zmuszony do pętli – Twelfth

+0

Tak, będziesz musiał loop - jak stwierdzono. –

+0

To nie jest najmilsze rozwiązanie, ponieważ przenosi problem z ustawionego poziomu teoretycznego na poziom proceduralny i dlatego może być używane tylko jako przygotowanie, a nie w czasie rzeczywistym (odpowiada na moje "lub", a nie moje "albo" pytanie), ale przynajmniej działa . Dzięki. :) – AndreKR

0

Można również użyć REGEXP

SET @materialids=SELECT material FROM parttable where part_id=1; 
SELECT * FROM material_id WHERE REGEXP CONCAT('^',@materialids,'$'); 

Pomoże to jeśli chcesz dostać tylko jeden pa rt. Nie cała tabela oczywiście

+6

Dziękuję za odpowiedź, ale myślę, że twój SQL nie ma sensu. :) – AndreKR

1

MySQL nie ma tymczasowego ponownego użycia tabel, a funkcje nie zwracają wierszy.

Nie mogę znaleźć niczego w Stack Overflow, aby przekonwertować ciąg liczb całkowitych csv na wiersze, więc napisałem własne w MySQL.

DELIMITER $$ 

DROP PROCEDURE IF EXISTS str_split $$ 
CREATE PROCEDURE str_split(IN str VARCHAR(4000),IN delim varchar(1)) 
begin 
DECLARE delimIdx int default 0; 
DECLARE charIdx int default 1; 
DECLARE rest_str varchar(4000) default ''; 
DECLARE store_str varchar(4000) default ''; 

create TEMPORARY table IF NOT EXISTS ids as (select parent_item_id from list_field where 1=0); 
truncate table ids; 
set @rest_str = str; 
set @delimIdx = LOCATE(delim,@rest_str); 
set @charIdx = 1; 
set @store_str = SUBSTRING(@rest_str,@charIdx,@delimIdx-1); 
set @rest_str = SUBSTRING(@rest_str from @delimIdx+1); 

if length(trim(@store_str)) = 0 then 
    set @store_str = @rest_str; 
end if;  


INSERT INTO ids 
SELECT (@store_str + 0); 

WHILE @delimIdx <> 0 DO 
    set @delimIdx = LOCATE(delim,@rest_str); 
    set @charIdx = 1; 
    set @store_str = SUBSTRING(@rest_str,@charIdx,@delimIdx-1); 
    set @rest_str = SUBSTRING(@rest_str from @delimIdx+1); 

select @store_str; 
    if length(trim(@store_str)) = 0 then 
     set @store_str = @rest_str; 
    end if;  
    INSERT INTO ids(parent_item_id) 
    SELECT (@store_str + 0);`enter code here` 
END WHILE; 

select parent_item_id from ids; 
end$$ 
DELIMITER ; 

call str_split('1,2,10,13,14',',') 

Potrzebny będzie również do oddania do różnych typów, jeżeli nie używasz ints.

Powiązane problemy