MySQL запросы между таблицами

Discussion in 'PHP' started by slesh, 11 Feb 2011.

  1. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Собственно говоря столкнулся с одной проблемкой, необходимо получить данные в один запрос.
    Суть дела такова что есть 3 таблицы:
    1) Soft - содержит имя софта и номер
    • id INT PRIMARY KEY
    • name VARCHAR(32)

    2) Langs - содержит инфу о языке
    • id INT PRIMARY KEY
    • name VARCHAR(32) // имя языка
    • main INT // главный или нет
    если main = 1 значит язык является главным. main = 1 есть только у одного языка и всегда присутствует.

    3) Info - содержит описание софта
    • id INT PRIMARY KEY
    • soft_id INT FOREIGN KEY REFERENCES Soft(id)
    • lang_id INT FOREIGN KEY REFERENCES Langs(id)
    • data TEXT

    т.е. структура такая: Langs - список языков, Soft - список софта, Info - инфа о софте, на разных языках.

    И вот основная проблема: необходимо выбрать данных из Info зная soft_id и lang_id, но если в таблице отсутствует описание для указанного lang_id, то брать описание для языка у которого main = 1.
    И всё это необходимо провернуть в один запрос.
    Пытался завернуть всё в хранимую процедуру, но результат чуть не тот получается. Да и желательно без хранимых процедур.

    Даже не представляю как это завернуть в один запрос.
    Пытался по быдлокодовки написать чтото типа:

    Code:
    
    SELECT * FROM `Info` 
    	WHERE `soft_id` = НОМЕР_СОФТА 
    	HAVING `lang_id` = НОМЕР_ЯЗЫКА OR 
    		`lang_id`=(SELECT `id` FROM `langs` WHERE `main` = 1)
    
    
    Но такая конструкция пашет только если указан не найденный НОМЕР_ЯЗЫКА.
     
  2. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Единственный рабочий вариант который я придумал это только
    Code:
    SELECT * FROM `Info`
    	WHERE `soft_id` = НОМЕР_СОФТА AND
    		 `lang_id`=НОМЕР_ЯЗЫКА 
    UNION SELECT * FROM `Info`
    	WHERE `soft_id` = НОМЕР_СОФТА AND 
    		`lang_id`=(SELECT `id` FROM `Langs` WHERE `main`=1)
    LIMIT 1
    
    Но увы это самое полное извращение.
    Или даже так записать
    Code:
    SELECT * FROM `Info`
    	WHERE `soft_id` = НОМЕР_СОФТА AND
    		 `lang_id`=НОМЕР_ЯЗЫКА 
    UNION SELECT `Info`.* FROM `Info`, `Langs`
    	WHERE `soft_id` = НОМЕР_СОФТА AND 
    		`Info`.`lang_id`=`Langs`.`id` AND 
    		`Langs`.`main`=1
    LIMIT 1
    
    Но всё равно это не оптимизированное извращение выходит.
     
    #2 slesh, 11 Feb 2011
    Last edited: 11 Feb 2011
  3. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    slesh
    Code:
     SELECT * FROM `Info` WHERE `soft_id`=1 AND (`lang_id` in (SELECT `id` FROM `langs` WHERE `lang_id` = 1 or `main` = 1 ORDER BY `main` desc));
     
    _________________________
    1 person likes this.
  4. Chaak

    Chaak Elder - Старейшина

    Joined:
    1 Jun 2008
    Messages:
    1,059
    Likes Received:
    1,067
    Reputations:
    80
    Code:
    SELECT     Soft.name, Langs.name, Info.data
    FROM         Info INNER JOIN
                          Langs ON Info.lang_id = Langs.id INNER JOIN
                          Soft ON Info.soft_id = Soft.id
    WHERE     (Info.soft_id = 2) AND 
    (Info.lang_id = 6 OR Info.lang_id = (SELECT main_lang_id FROM Soft WHERE Soft.id = 2))
    Запрос вернет 1+ строк. В первой будет нужная инфа.

    main_lang_id - колнка в таблице Soft с главным языком приложения.
    Из таблицы lang его можно удалить.
     
    #4 Chaak, 11 Feb 2011
    Last edited: 11 Feb 2011
    1 person likes this.
  5. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,194
    Reputations:
    252
    JOIN !
     
  6. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Решил не париться с делать чуть по другому:
    Первый язык в таблице Langs - главный.
    И выборка идет по типу:
    SELECT * FROM Info WHERE soft_id = НОМЕР_СОФТА AND (lang_id = НОМЕР_ЯЗЫКА OR lang_id=1) ORDER BY lang_id DESC LIMIT 1
    По любому будет получено 1 значение из базы которое будет или ножным языком или первым языком
     
  7. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,194
    Reputations:
    252
    Я только создал таблицы...
     
  8. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 Isis Тут как бы еще дело скорости идет. Хотя мне будет интересно посмотреть и на твой вариант.