Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MySQL > Помогите с запросом


Автор: Staser 28.10.2006, 03:22
Как сделать нормальный (правильно работающий) запрос типа SELECT COUNT(*)...;

Из такого вот запроса:
Код

SELECT DISTINCT
    `uid`,
    `fid`
FROM
    `list`
WHERE
    `uid` IN (
SELECT DISTINCT
    `uid`
FROM
    `list`
WHERE
    `fid` IN (
SELECT DISTINCT
    `uid`
FROM
    `list`
WHERE
    `fid`=%ID% )
    AND
        `fid`!=%ID% )
    AND
        `fid`!=%ID%
    AND
        `list`.`fid` NOT IN (
SELECT
    `fid`
FROM
    `list`
WHERE
    `uid`=%ID% )
    AND 
        `list`.`fid` NOT IN (
SELECT
    `fid`
FROM
    `list`
WHERE
    ( `uid` IN (
SELECT
    `uid`
FROM
    `list`
WHERE
    `fid`=%ID% ) ) )
GROUP BY
    `fid`
LIMIT
    6


Проблемы которые следует решить:
  •  При 0 кол-ве (отсутствии записей 3го уровня), должно возвращать COUNT(*) -> 0 однако невозвращает ничего. (0 рядов)
  •  При наличии более одного пути к данной зависимости выводит их все, при простом выводе от этого спасает простая группировка, однако при выборе COUNT, насчитывает лишние пути..
  •  По возможности оптимизировать запрос

Автор: comtat 28.10.2006, 10:26
Какие ошибки заметил сразу 
Код
SELECT DISTINCT    `uid`,    `fid`, FROM    `list`

перед FROM запятой не нужно ставить
За чем нужна такая конструкция 
Код
`uid`=%ID%

Я не понимаю, наверное имелось в виду, если ID число, то тогда  
Код
`uid`=ID

Автор: Staser 28.10.2006, 13:17
Первая ошибка, это я не заметил когда вырезал _лишнее_ из запроса, важна сама суть...
%ID% - это некая переменная в скрипте, который делает запрос...

И всёже, так никто и не помог, вопрос тот же...

Автор: muzer 28.10.2006, 16:13
Staser, вы издеваетесь? smile

Подскажу, как правильно задать вопрос:
привести show create table, описать какое поле что значит, сформулировать словами, какого результата пытаетесь добиться, тогда вам помогут. 

А то представьте, я щас приведу какой-нить запрос (типа того, что ниже) и скажу "помогите, не работает" smile
Код

SELECT
        T.NeedInfo1,
        T.NeedInfo3,
        T.NeedInfo2,
        L.SomeVal
FROM
(
        SELECT
                H.SomeTopValID,
                H.SomeValID,
                SUM(S.NeedInfo1) AS NeedInfo1,
                SUM(S.NeedInfo3) AS NeedInfo3,
                H.NeedInfo2
        FROM
        (
                SELECT
                        SomeTopValID,
                        SomeValID,
                        COUNT(*) AS NeedInfo2
                FROM
                        SomeValHistory
                WHERE
                                SomeTopValID = $SomeTopValid
                        AND
                                SomeTime1 > NOW() - INTERVAL 3 DAY
                GROUP BY
                        SomeValID
        ) H
        INNER JOIN
                SomeValStat S
                USING(SomeTopValID,SomeValID)
        WHERE
                S.SomeTime2 > NOW() - INTERVAL 3 DAY
        GROUP BY
                SomeValID
        ORDER BY
                NeedInfo2 DESC
        LIMIT
                $limit
) T
INNER JOIN
        SomeValLog L
        USING(SomeTopValID,SomeValID)
ORDER BY
        T.NeedInfo2 DESC

Автор: Staser 28.10.2006, 18:41
 smile 

Ну вот таблица, (значительно упрощённая)
Код

CREATE TABLE `list` (
  `uid` int(11) NOT NULL,
  `fid` int(11) NOT NULL,
  KEY `uid` (`uid`,`fid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci

Представляет собой таблицу зависимостей,
 где `uid` владелец
 где `fid` тот кто напрямую относится к владельцу
 если `uid`=1, и у него есть прямое отношение к пользователю, скажем, 3 (`fid`=3) то у пользователя 3 должна быть соответствующая запись, только наоборот, `uid`=3, `fid`=1

А запрос, приведённый выше (1ый пост), находит и выводит с помощью рекурсии все связи 4го уровня

Вот графическая запись того что делается..
1. user posted image 2. user posted image

1. Всё работает правильно
2. Выбор записей, SELECT `uid`, `fid`... работает правильно, с группировкой:
 uid  fid  
  4    3 
  5    7 
  5    8 

    Выбор кол-ва записей выводит несколько результатов работы COUNT, в то время когда нужен 1
COUNT( * )  
1 
2 

Проблемы:
  •  При 0 кол-ве (отсутствии записей 3го уровня), должно возвращать COUNT(*) -> 0 однако невозвращает ничего. (0 рядов)
  •  При наличии более одного пути к данной зависимости выводит их все, при простом выводе от этого спасает простая группировка, однако при выборе COUNT, насчитывает лишние пути..


Вот структура базы для приведённых примеров:
1.
Код

INSERT INTO `list` (`uid`, `fid`) VALUES 
(1, 2),
(2, 1),
(2, 4),
(3, 4),
(4, 2),
(4, 3);

2.
Код

INSERT INTO `list` (`uid`, `fid`) VALUES 
(1, 2),
(2, 1),
(2, 4),
(2, 5),
(2, 6),
(3, 4),
(4, 2),
(4, 3),
(5, 2),
(5, 7),
(5, 8),
(6, 2),
(6, 8),
(7, 5),
(8, 5),
(8, 6);


Уфф, надеюсь понятно обьяснил... smile 

Автор: muzer 28.10.2006, 22:55
Вот, уже лучше. Вы только не написали, какой должен быть результат у запроса для тех данных, которые вы привели в примере.

Очередная пирамида? smile Впрочем неважно.
Я так понимаю для данного uid'а (%ID%) вам нужно вывести либо кол-во всех его рефералов третьего уровня, либо просто ввывести всех рефералов или что-то другое нужно?

1. У вас много избыточной информации, её можно сократить вдвое. Мы оставим например только записи вида uid=3 fid=1 для случая, когда юзер 3 зависим от 1.
2. Выбрать всех рефералов третьего уровня:
SELECT DISTINCT uid FROM list WHERE fid IN (SELECT DISTINCT uid FROM list WHERE fid IN (SELECT uid FROM list WHERE fid=%ID%));
3. Выбрать кол-во рефералов третьего уровня:
SELECT COUNT(DISTINCT uid) FROM list WHERE fid IN (SELECT DISTINCT uid FROM list WHERE fid IN (SELECT uid FROM list WHERE fid=%ID%));
4. Выбрать кол-во рефералов третьего уровня в разбивке по рефералам второго уровня:
SELECT fid,COUNT(uid) FROM list WHERE fid IN (SELECT DISTINCT uid FROM list WHERE fid IN (SELECT uid FROM list WHERE fid=%ID%)) GROUP BY fid;

Но все эти решения достаточно просты, из этого следует одно из двух: либо вы слишком запутали задачу и запутались в итоге сами, либо я не понял, какой результат вы хотите получить при выполнении запроса..

Ну и ещё рекомендую пересмотреть структуру таблицы, если вам юудут нужны выборки такого вида. Почитайте про способы организации деревьев в базах данных.

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