mysql выбирает строки с одинаковыми идентификаторами и сохраняет их порядок?

просто быстрый вопрос:

у меня должен быть один запрос с несколькими строками - некоторые строки идентичны - и порядок строк должен быть сохранен в результате -

некоторое представление о том, что я имею в виду:

SELECT id,date 
FROM items 
WHERE id IN (1,2,1,3) 
ORDER BY id=1 DESC,id=2 DESC,id=1 DESC,id=3 DESC;

к сожалению, результат mysql таков:

1,2,3

не 1,2,1,3

он удаляет дубликат, который я должен иметь в своем результате для отображения на нескольких панелях на одной и той же веб-странице -

я действительно не хочу перебирать каждый идентификатор один за другим, чтобы получить их так, как я хочу отображать -

есть ли способ на самом деле иметь один единственный запрос, который сохранит порядок и вытянет строки на основе запроса, независимо от того, уникален он или нет -


person user1228311    schedule 23.02.2012    source источник
comment
Я думаю, что ваш дизайн модели данных не так хорош. Был ли у вас первичный ключ в качестве автоинкремента?   -  person rkosegi    schedule 23.02.2012
comment
да - идентификатор автоматически увеличивается в таблице БД -   -  person user1228311    schedule 23.02.2012
comment
дубликат stackoverflow.com/questions/1109113/   -  person lamplightdev    schedule 23.02.2012
comment
Если id автоматически увеличивается, то возможных повторяющихся строк не существует, так что вы подразумеваете под WHERE id IN (1,2,1,3) - у вас есть 2 раза id = 1   -  person rkosegi    schedule 23.02.2012
comment
это была абстрактная идея для описания результата, который мне нужно вывести - если это сбивает с толку, то моя искренняя апология -   -  person user1228311    schedule 23.02.2012
comment
Вы потенциально должны были описать свою конкретную проблему, а не реферат. Если вы описываете свою конкретную проблему, то ваши ответы будут более подходящими. Если вы попытаетесь обобщить, все может потеряться. Кроме того, будучи конкретным, вы открываете пространство для альтернативных методов, которые могут дать лучший способ достичь той же цели. Обычно есть несколько путей к одному и тому же месту назначения.   -  person Simon at My School Portal    schedule 25.02.2012


Ответы (6)


Ваш запрос в его нынешнем виде никогда не будет работать, потому что повторяющиеся значения в списке значений предложения IN игнорируются. Единственный способ заставить это работать — использовать UNION ALL:

SELECT id, date FROM items where id = 1
UNION ALL
SELECT id, date FROM items where id = 2
UNION ALL
SELECT id, date FROM items where id = 1
UNION ALL
SELECT id, date FROM items where id = 3;

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

person Bohemian♦    schedule 23.02.2012
comment
Я согласен с вашим последним мнением - person Simon at My School Portal; 23.02.2012
comment
Это не единственный способ. Есть и другие. - person glglgl; 23.02.2012

пытаться

SELECT
    id,
    date
FROM items
WHERE id IN (1,2,1,3)
ORDER BY FIND_IN_SET(id, '1,2,1,3')
person silly    schedule 23.02.2012
comment
Будет сортировать 1,1,2,3, так как значения FIND_IN_SET() равны 1,2,1,4. - person glglgl; 23.02.2012

Еще один щепетильный способ ответить на подозрительный вопрос:

SELECT 
      items.id, 
      items.date 
FROM 
      items 
  JOIN
      ( SELECT 1 AS id, 1 AS ordering
      UNION ALL 
        SELECT 2, 2
      UNION ALL 
        SELECT 1, 3
      UNION ALL 
        SELECT 3, 4
      ) AS auxilary
    ON 
      auxilary.id = items.id 
ORDER BY 
      auxilary.ordering
person ypercubeᵀᴹ    schedule 23.02.2012

Другой подход (непроверенный, но должен дать вам представление):

CREATE TEMPORARY TABLE tt (id INT, ai int unsigned auto_increment primary key);
INSERT INTO tt (id) VALUES (1), (2), (1), (3);
SELECT
    id,
    date
FROM items JOIN tt USING (id)
ORDER BY tt.ai;

соблюдает заданный порядок.

person glglgl    schedule 23.02.2012
comment
Аналогично моему ответу. Но вам нужно 2 столбца в таблице temp. Один для присоединения и один для заказа. - person ypercubeᵀᴹ; 23.02.2012
comment
Ой, у вас есть 2 столбца! Значения должны быть: VALUES (1), (2), (1), (3) - person ypercubeᵀᴹ; 23.02.2012
comment
У меня - у меня id и ai (для автоинкремента), у вас id и ordering. Но temptable, вероятно, более удобен для вставки данных, т.е. е. запрос легче построить, в зависимости от используемого языка программирования. - person glglgl; 23.02.2012
comment
Это предложение было бы довольно болезненным, использование временной таблицы там, где это не нужно, является излишним. - person Simon at My School Portal; 25.02.2012
comment
ИМО, это не так болезненно, как создание запроса, содержащего десятки UNION оргий... - person glglgl; 25.02.2012

Если вы хотите включить записи с id = 1, и порядок не имеет значения, пока вы их получаете, вы можете разделить свой запрос на два запроса, один для (1,2,3) объединить все остальные запросы для id =1 или просто выполните:

... In (1,2)
Union all
... In (1,3)

Пример:

  Select * from
  (Select case id when 1 then 1 when 2 then 2 as pseudocol, othercolumns
  From table where Id in (1,2)
  Union all
  Select case id when 1 then 3 when 3 then 4 as pseudocol, othercolumns
  From table where Id in (1,3)) t order by pseudocol
person Icarus    schedule 23.02.2012
comment
порядок имеет существенное значение, ребята. - person user1228311; 23.02.2012
comment
Вариант union all, который я написал как последний вариант, вернет записи в том порядке, в котором вы хотите. Вы пробовали? - person Icarus; 23.02.2012
comment
спасибо, icarus - у меня проблема с объединением всех вышеперечисленных stmt - он не вернет тот же порядок - я должен иметь порядок на месте - поэтому все результаты упорядочены туда и обратно - person user1228311; 23.02.2012
comment
Чувак, затем добавь псевдостолбец в операторы выбора, который указывал бы нужный порядок, и псевдоним всего союза, и делай порядок в этом псевдостолбце. - person Icarus; 23.02.2012
comment
@user1228311 user1228311 проверьте мой последний пример - person Icarus; 23.02.2012
comment
я сдаюсь - на этой странице ничего не работает - либо выдается ошибка mysql, либо ноль результатов из вышеуказанных запросов - поэтому мне пришлось использовать цикл для выбора элементов один за другим - их 10 штук - может быть больше, поэтому я должен продолжайте искать правильный запрос - может быть, кто-нибудь в конце концов напишет запрос, который работает безупречно - здесь нет обид, и я ценю каждый ответ выше - - person user1228311; 23.02.2012

Вместо того, чтобы делать то, что вы пытаетесь сделать, просто выберите нужные уникальные строки. В коде внешнего интерфейса сохраните каждую уникальную строку один раз в структуре ключ => значение, где ключ — это идентификатор элемента, а значение — любые данные, которые вам нужны об этом элементе.

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

Например, Это непригодный для использования код — требуемый синтаксис зависит от вашего языка сценариев.

-- setup a display order
displayOrder= [1,2,1,3];

-- select data from database, order doesn't matter here
SELECT id,date 
FROM items 
WHERE id IN (displayOrder);


-- cache the results in a key=> value array
arrCachedRows = {};
for (.... each db row returned ...) {
    arrCachedRows[id] = date;
}

-- Now output in desired order
for (listIndex in displayOrder) {
    -- Make sure the index is cached
    if (listIndex exists in arrCachedRow) {
        echo arrCachedRows[listIndex ];
    }
}

Если вы продолжаете использовать UNION, несмотря на мои предупреждения

Если вы идете против приведенной выше рекомендации и абсолютно ДОЛЖНЫ вернуть их в 1 запрос в этом порядке, добавьте дополнительную строку, которая обеспечит соблюдение порядка строк. См. ниже запрос, в котором я использую переменную @subIndex для добавления возрастающего значения в качестве subIndex. Это, в свою очередь, позволяет вам изменить порядок, и он будет в запрошенном порядке.

SELECT
    i.*
FROM (
    SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 1
    UNION
    SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 2
    UNION
    SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 1
    UNION
    SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 3
) AS i,(SELECT @subIndex:=0) v
ORDER BY i.subIndex

Или немного более чистая версия, которая сохраняет выбор элемента снаружи и скрывает субиндекс.

SELECT
    items.*
FROM items
-- initialise variable
INNER JOIN (SELECT @subIndex:=0) v
-- create a meta-table with the ids desired in the order desired
INNER JOIN (
    SELECT @subIndex:=@subIndex+1  AS subIndex, 1 AS id
    UNION
    SELECT @subIndex:=@subIndex+1  AS subIndex, 2 AS id
    UNION
    SELECT @subIndex:=@subIndex+1  AS subIndex, 1 AS id
    UNION
    SELECT @subIndex:=@subIndex+1  AS subIndex, 3 AS id
) AS i
ON i.id = items.id
-- order by the subindex from i
ORDER BY i.`subIndex` ASC
person Simon at My School Portal    schedule 23.02.2012
comment
как я уже сказал - я действительно не хочу перебирать каждый идентификатор один за другим, чтобы получить их так, как я хочу отображать - - person user1228311; 23.02.2012
comment
Вы определяете свой порядок отображения только один раз. Вы можете получить тот же эффект, используя UNION и т. д., однако он будет менее эффективным и менее масштабируемым. Используя этот метод, не имеет значения, сколько идентификаторов вы добавите в displayOrder, он будет работать. - person Simon at My School Portal; 23.02.2012
comment
спасибо Саймон - у меня проблема с объединением всех вышеперечисленных stmt - он не вернет тот же порядок - я должен иметь порядок на месте - поэтому все результаты упорядочены туда и обратно - - person user1228311; 23.02.2012
comment
Итак, ORDER BY i.index ASC - выдаст новый ордер, на который он похож, или сохранит первоначальный ордер? Пожалуйста, уточните это - спасибо! - person user1228311; 23.02.2012
comment
@subIndex:=@subIndex+1 добавляет столбец, который увеличивается, то есть 1, 2, 3, 4, который я назвал subIndex в подзапросе i. Затем это считается статическим во внешнем запросе, поэтому ORDER BY i.index ASC. id по-прежнему будут в том порядке, который вы указали в построенном UNION, пока вы включаете этот ORDER BY i.subIndex ASC - person Simon at My School Portal; 23.02.2012
comment
Подзапрос существует только для того, чтобы упорядочить поля в нужном вам порядке. Он присоединяется к таблице items, поэтому вы можете изменять запрашиваемые поля во внешней таблице SELECT, то есть вместо SELECT items.* вы можете использовать SELECT items.id, items.date или любые другие поля из таблицы элементов. - person Simon at My School Portal; 23.02.2012