Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Составление SQL-запросов > Сложный запрос - проще показать, чем объяснить :)


Автор: PashaLost 5.7.2012, 23:32
Добры день, Господа !
Подскажите, как составить SELECT-запрос (именно запроc, а не что-нибудь другое) из следующей структуры таблиц БД: 
1) Имеем:
       Таблицу Games - хранит информацию об игре. 
       Таблицу Rounds - (одной игре  соответствует несклолько раундов) хранит информацию о раундах
       Таблицу Cards - (одному раунду соответствует несколько карт) хранит информацию о картах 
2) Необходимо: 
      Написать ОДИН SELECT запрос, который выведет информацию из трёх таблиц в одну ТАК, чтобы в первом стобце размещалась информация об игре, во втором столбце размещалась информация о ПЕРВОМ раунде игры, в следующем - информация о всех картах ПЕРВОГО раунда, следующем информация о ВТОРОМ раунде и т.д. 

НАДЕЮСЬ, суть вопроса прояснится больше  из картинки ниже smile 
Проблему можно решить с помощью временной таблицы, пробежаться курсором по всем записям и бла бла бла 
но это ОЧЕНЬ медленно, и каждый раз нужно очищать и записывать в таблицу - а если записей несколько тысяч - тогда вообще кирдык. А подготовленный запрос бы с этим справился. 

user posted image

Автор: Gluttton 5.7.2012, 23:40
Колличество столбцов с Round и Cards переменное или всегда равно 4?

Автор: PashaLost 6.7.2012, 01:10
Количество столбцов всегда одинаково (раундов всегда 4), однако самих раундов всех 4 в одной игре может не существовать (тогда записывать NULL), количество карт во втором раунде - 3 (всех их нужно запихивать в одну ячейку функцией GROUP_CONCAT) в других по одной (но это не важно что одна - нужно всё равно суммировать все имеющиеся в одном раунде)

Автор: Gluttton 6.7.2012, 01:19
К сожалению нет под рукою SQL-сервера и я не погу проверить предлагаемое решение...

Суть в следующием:
С таблицей Games производить LEFT JOIN вот таких вот подапросов:
Код

(
    select * from Roudns where info = RoundInfo2
)   as subRoudnInfo2


Т.е. что то вроде такого:
Код

select
    Games.Info,
    subRoundInfo1.Info,
    subRoundInfo2.Info,
    ...
from Games
    left join (
        select * from Rounds where Info = RoundInfo1
    )   as subRoundInfo1
    on Games.ID = subRoundInfo1.GamesID
    left join (
    ...
    )   as subRoundInfo2
    ...

Автор: Gluttton 6.7.2012, 11:45
Решение для Firebird 2.5.

Скрипт для создания БД, таблиц, первиных и вторичных ключей, а так же заполнения тестовыми данными.
Код

SET AUTODDL ON;


CONNECT '/home/Gluttton/Projects/databases/firebird/VingradPashaLostCards.fdb'
USER 'SYSDBA' PASSWORD 'masterkey';
DROP DATABASE;

SET SQL DIALECT 3;
SET NAMES UTF8;
CREATE DATABASE '/home/Gluttton/Projects/databases/firebird/VingradPashaLostCards.fdb'
USER 'SYSDBA' PASSWORD 'masterkey' 
PAGE_SIZE 16384 DEFAULT CHARACTER SET UTF8;


CREATE DOMAIN ID     AS BIGINT           NOT NULL;
CREATE DOMAIN INFO   AS VARCHAR (32);


CREATE TABLE GAMES
(
    ID       ID,
    INFO     INFO
);

CREATE TABLE ROUNDS
(
    ID       ID,
    GAME_ID  ID,
    INFO     INFO
);

CREATE TABLE CARDS
(
    ID       ID,
    ROUND_ID ID,
    INFO     INFO
);

COMMIT;


ALTER TABLE GAMES  ADD CONSTRAINT PK_GAMES  PRIMARY KEY (ID);
ALTER TABLE ROUNDS ADD CONSTRAINT PK_ROUNDS PRIMARY KEY (ID);
ALTER TABLE CARDS  ADD CONSTRAINT PK_CARDS  PRIMARY KEY (ID);

COMMIT;


ALTER TABLE ROUNDS ADD CONSTRAINT FK_GAMES_ROUNDS FOREIGN KEY (GAME_ID)  REFERENCES GAMES  (ID);
ALTER TABLE CARDS  ADD CONSTRAINT FK_ROUNDS_CARDS FOREIGN KEY (ROUND_ID) REFERENCES ROUNDS (ID);

COMMIT;



INSERT INTO GAMES (ID, INFO) VALUES (1, '1');
INSERT INTO GAMES (ID, INFO) VALUES (2, '2');
INSERT INTO GAMES (ID, INFO) VALUES (3, '3');
INSERT INTO GAMES (ID, INFO) VALUES (4, '4');

COMMIT;

INSERT INTO ROUNDS (ID, GAME_ID, INFO) VALUES (1, 1, '1');
INSERT INTO ROUNDS (ID, GAME_ID, INFO) VALUES (2, 1, '2');
INSERT INTO ROUNDS (ID, GAME_ID, INFO) VALUES (3, 2, '3');

COMMIT;

INSERT INTO CARDS (ID, ROUND_ID, INFO) VALUES (1, 1, '1');
INSERT INTO CARDS (ID, ROUND_ID, INFO) VALUES (2, 1, '2');
INSERT INTO CARDS (ID, ROUND_ID, INFO) VALUES (3, 2, '3');

COMMIT;


Запрос:
Код

select
    GAMES.INFO as Game,
    R1.INFO    as Round_I,
    R1.CARDS   as Cards_I,
    R2.INFO    as Round_II,
    R2.CARDS   as Cards_II,
    R3.INFO    as Round_III,
    R3.CARDS   as Cards_III,
    R4.INFO    as Round_IV,
    R4.CARDS   as Cards_IV

from GAMES
    left join (
        select
            ROUNDS.GAME_ID,
            ROUNDS.INFO,
            list (CARDS.INFO) as CARDS
        from ROUNDS left join CARDS
            on ROUNDS.ID = CARDS.ROUND_ID
            where ROUNDS.INFO = '1'
        group by ROUNDS.GAME_ID, ROUNDS.INFO
    )   as R1
    on GAMES.ID = R1.GAME_ID

    left join (
        select
            ROUNDS.GAME_ID,
            ROUNDS.INFO,
            list (CARDS.INFO) as CARDS
        from ROUNDS left join CARDS
            on ROUNDS.ID = CARDS.ROUND_ID
            where ROUNDS.INFO = '2'
        group by ROUNDS.GAME_ID, ROUNDS.INFO
    )   as R2
    on GAMES.ID = R2.GAME_ID

    left join (
        select
            ROUNDS.GAME_ID,
            ROUNDS.INFO,
            list (CARDS.INFO) as CARDS
        from ROUNDS left join CARDS
            on ROUNDS.ID = CARDS.ROUND_ID
            where ROUNDS.INFO = '3'
        group by ROUNDS.GAME_ID, ROUNDS.INFO
    )   as R3
    on GAMES.ID = R3.GAME_ID

    left join (
        select
            ROUNDS.GAME_ID,
            ROUNDS.INFO,
            list (CARDS.INFO) as CARDS
        from ROUNDS left join CARDS
            on ROUNDS.ID = CARDS.ROUND_ID
            where ROUNDS.INFO = '4'
        group by ROUNDS.GAME_ID, ROUNDS.INFO
    )   as R4
    on GAMES.ID = R4.GAME_ID


Результат.
Цитата

GAME  ROUND_I  CARDS_I  ROUND_II  CARDS_II  ROUND_III  CARDS_III  ROUND_IV  CARDS_IV
1     1        1,2      2         3         NULL       NULL       NULL      NULL
2     NULL     NULL     NULL      NULL      3          NULL       NULL      NULL
3     NULL     NULL     NULL      NULL      NULL       NULL       NULL      NULL
4     NULL     NULL     NULL      NULL      NULL       NULL       NULL      NULL


Но назвать решение изящным язык не аж никак не поварачивается...

Автор: PashaLost 9.7.2012, 00:53
Спасибо Gluttton, потребовалось немного времени, чтобы скореллировать вашу идею на реальный проект бд (не тот что в примере), и оно таки заработало ! smile  Если бы хватило прав, то поставил бы "+" 

Автор: Gluttton 9.7.2012, 12:13
Цитата(PashaLost @  9.7.2012,  00:53 Найти цитируемый пост)
Спасибо Gluttton

Пожалуйста!

Цитата(PashaLost @  9.7.2012,  00:53 Найти цитируемый пост)
Если бы хватило прав, то поставил бы "+"  


Цитата(PashaLost @  9.7.2012,  00:53 Найти цитируемый пост)
и оно таки заработало !

Это и есть для меня самый большой "+" ;) .

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)