Какой самый худший SQL-запрос вы когда-либо видели? Что сделало это плохим?
У него определенно достаточно репутации, чтобы сделать свой вопрос вики. Wikify это.
Выделение того, что составляет плохую практику программирования, - это про программирование (и в большей степени, чем некоторые другие нежелательные темы, которые я видел)
@mitch: Это не вопрос, на который можно дать хотя бы отдаленно однозначный ответ. Напротив, это вопрос, на который ожидается много обоснованных ответов. Ergo: вики.
Я только что нашел худший пост на свете.


выберите из *
Очень плохо.
ВЫБРАТЬ * ИЗ * ГДЕ * = '%%'; я не смею проверять, действительно ли это работает.
или любое перекрестное соединение между двумя или более достаточно большими таблицами.
перекрестное соединение между двумя большими, но узкими таблицами часто является оптимальным решением, например, для сопоставления наборов - многие ко многим - распространенная проблема
Конечно, классический xkcd:
WHERE name = ROBERT'); DROP TABLE students;--
Почему вы получили за это отрицательные голоса? Это весело!
О, кто-то снял свой отрицательный голос.
Мы называем его Little Bobby Tables
Как это считается «худшим»? Это великолепно.
Величие не в запросе, а в названии :)
Клиент хранил список из трех значений, разделенных запятыми, в поле varchar (классическое приложение ASP), поэтому у него была хранимая процедура, которая выглядела примерно так:
SELECT *
FROM
SomeTable
WHERE
Field LIKE @Param + ',%'
OR
Field LIKE '%,' + @Param + ',%'
OR
Field LIKE '%,' + @Param
Должно быть очевидно, почему это ужасно :)
ай! От этого у меня болят зубы!
Я видел похожие вещи в большой производственной программе: S
Есть ли лучший способ написать это?
Не знаю, подходящее ли слово лучше, но - WHERE ',' + Field + ',' LIKE '%,' + @Param + ',%' - вероятно, будет работать быстрее. Конечно, у вас не должно быть данных, разделенных запятыми, внутри полей в СУБД.
Недавно я видел (более чем) 4000-строчную хранимую процедуру TSQL, которая представляла собой цепочку статусов IF для сопоставления частей адресов. Его можно сократить до менее чем 50 строк!
Сохраняю код для будущего DailyWTF!
SELECT * FROM some_table;
Что сделало это настолько плохим, так это то, что код полагался на получение результатов в порядке на основе отметки времени. Это, по-видимому, работало какое-то время, прежде чем меня вызвали, чтобы это исправить.
DELETE FROM table
Сразу после того, как я напечатал и выполнил его, я забыл о предложении WHERE. Теперь я всегда сначала запускаю оператор SELECT и меняю SELECT на DELETE после того, как убедился, что это повлияет на правильные строки.
Ой ..! Я параноик, я всегда окружаю операторы обновления / удаления командами begin tran / rollback, пробую и затем выполняю внутреннюю часть, когда чувствую себя в безопасности.
Я делаю нечто подобное, за исключением того, что просто пишу TableName как TableNameFOO, пока пишу его. Я также оставляю поле "Кому:" для писем пустым, прежде чем напишу все письмо и вычитаю его ... на всякий случай;)
@ocdecio: Это был MySQL, до того, как они поддерживали транзакции :(
@sean: у меня есть коллега, который запускает операторы DELETE с WHERE 1 = 0 на тот случай, если они забудут добавить правильное предложение WHERE до того, как нажмут кнопку выполнения. Точно так же я поступаю с электронной почтой.
То же самое, и меня поражает, как часто я получаю результат, отличный от ожидаемого.
Ребята ... выберите * в z_backup из <important table> в качестве первого шага. Тогда иди с ума.
Я делал это раньше, пока работал, к счастью, я работал на сервере разработки и только что восстановил последнюю резервную копию базы данных. Я также недавно написал веб-страницу для управления образовательным статусом сотрудников и пропустил пункт where. Скажем так, у всех есть ученая степень.
ха-ха. Я всегда начинаю с BEGIN на производстве.
Вот почему я считаю, что команды DELETE и INSERT должны требовать от программиста явного выражения своего намерения применить оператор ко всем строкам, например УДАЛИТЬ ВСЕ ИЗ таблицы
Ой. Я сам чувствовал эту боль. Один раз.
Однажды со мной случилось то же самое - я всегда сначала выбираю, а потом меняю запрос, когда доволен результатами.
То же самое и с UPDATE, особенно с таблицей, содержащей (лингвистические) переводы :)
select * from users where clue > 0;
0 results found.
Хуже всего в этом sql то, что он никогда не возвращает никаких результатов, независимо от того, где вы его запускаете
Вот почему мы должны иметь возможность голосовать за комментарии :)
Что происходит, почему вы запускаете этот запрос в базе данных Stack Overflow? Он по-прежнему возвращает 0 результатов? Или он просто возвращает идентификатор пользователя 22656
Почему этот плохой SQL? Зачем играть в стрелять в посыльного?
Вероятно, это не самое худшее, но я вижу это слишком часто (Неправильное использование группы by clause):
SELECT
C.CustomerID, C.CustomerName, C.CustomerType, C.Address1, C.City,
C.State, SUM(S.Sales) as TotalSales
FROM
Customers C
INNER JOIN Sales S
ON C.CustomerID = S.CustomerID
GROUP BY
C.CustomerID, C.CustomerName, C.CustomerType, C.Address1, C.City, C.State
Вместо:
SELECT
C.CustomerID, C.CustomerName,
C.CustomerType, C.Address1, C.City,
C.State, S.TotalSales
FROM
Customers C
INNER JOIN
(SELECT CustomerID, SUM(Sales) as TotalSales FROM Sales GROUP BY CustomerID) S
ON
C.CustomerID = S.CustomerID
Вызовите меня по этому поводу, но я не согласен с тем, что, как правило, 1 - это плохо, а 2 - хорошо. В более сложном примере поддерживать 2 становится немного сложнее. Для меня цель 1 очень ясна, и поэтому ее проще поддерживать. 2 может предложить лучшую производительность, но выигрыш того не стоит.
Кроме того, правило 2 работает медленнее под mysql. mysql--. последний еще более удобен в обслуживании, если вы его дизассемблируете и используете подстановку строк для составления окончательного запроса. ВНУТРЕННЕЕ СОЕДИНЕНИЕ ($ customerTotals): D
Не будет ли лишнего соединения с синтаксисом 2? Может иметь значение или не иметь значения
+1 за интересный рефакторинг - хороший момент. Версия 1 - это простой запрос до SQL-92, адаптированный для использования нотации соединения SQL-92. Второй не должен быть медленнее - он группирует в одной таблице, а затем объединяет ее с исходным (если, я полагаю, оптимизатор не упорядочивает результат подзапроса и не использует этот порядок в объединении слияния с клиентом table, и в этом случае это может быть медленнее, чем индексированное соединение).
Мое собственное, о котором еще далеко до публикации - сейчас закрывается на 3500 строках.
Я действительно должен разделить вину с абсолютно ужасной схемой. То, что начиналось как простое упражнение по преобразованию денормализованных данных с помощью некоторых объединений, превратилось в громоздкий кошмар. Сильно требует ремонта.
Второе место занял:
select
case datepart(mm,getdate())
when 1 then 'Jan'
when 2 then 'Feb'
when 3 then 'March'
when 4 then 'Apr'
when 5 then 'May'
when 6 then 'Jun'
when 7 then 'July'
when 8 then 'Aug'
when 9 then 'Sept'
when 10 then 'Otc'
when 11 then 'Nov'
when 11 then 'Dec'
end
В этом посте нет опечаток - так оно и было написано. Спасибо, консультации долларов!
Я, конечно, реорганизовал с помощью Select left (datename (mm, getdate ()), 3)
11 сопоставлены с ноябрем и декабрем ?? Действительно?
Мы обнаружили эту жемчужину в декабре.
На рабочем месте, которое останется безымянным, ваше исправление будет осуждено, потому что оно нарушает написание слов «сентябрь» и «март» (не говоря уже о том, что оно исправляет ошибку).
@Shivasubramanian: Да, в Otc была орфографическая ошибка; это один из моментов.
@TrickyNixon: преимущество этого решения в том, что оно не зависит от локали, поэтому даже французские, испанские, немецкие или японские пользователи вынуждены использовать английские сокращения для названий месяцев. : D
@ Джонатан, ах !! Спасибо что подметил это... ;-)
<сарказм> Разве все не говорят на американском английском? Ба! </sarcasm>
Джонатан Леффлер: Это тоже недостаток. Вполне возможно, что существует язык, в котором два месяца имеют одни и те же первые 3 буквы.
прочтите это вслух.
select [select],*,star as [as] from [from],[order] order by [by]
Это должно быть что-то вроде slashdot.org
Когда я впервые получил свою текущую работу, моим первым проектом было создание приложения, которое суммировало бы наши данные об использовании лицензий в наших компьютерных лабораториях. Он настаивал на том, что не хочет нормализовать серверную базу данных, потому что соединения были «слишком дорогими». Это была моя первая неделя, и я не мог спорить.
Теперь, чтобы извлечь какие-либо полезные данные из базы данных, нужно «отменить» денормализацию в каждом запросе, который должен извлекать сводки для удаления дублированных данных в каждой строке. Конечно, это единственные реально используемые запросы. Вы видите множество вложенных выборок, которые были бы совершенно ненужными, если бы данные были нормализованы, например:
select location, sum(login_time) as total_login_time
from
(select location, session_id, max(login_time) as login_time
from sessions
where location in ('lab1','lab2')
and session_start >= @start_date
and session_end <= @end_date
group by location, session_id) tbl
group by location
Хотя сам запрос не особенно уродлив - хотя некоторые из них - процесс необходимости каждый раз перепрыгивать через обручи, чтобы отменить ненужную денормализацию, больно.
Сейчас босса нет, а переписывать некогда ...
сделайте несколько просмотров, чтобы денормализовать данные для вас: D
Это неправильно на многих уровнях. Особенно замечание о том, что присоединение «слишком дорого».
УДАЛИТЬ ИЗ some_table WHERE some_thing IN (ВЫБЕРИТЕ some_column_from_wrong_table ИЗ правильной_таблицы, ГДЕ some_id = something).
В some_column_from_wrong_table есть столбец, которого даже не было в таблице, но он был в другой таблице. Проблема заключалась в том, что правильная_таблица была названа «Событие», и каким-то образом она вернула ВСЕ строки вместо НЕТ строк (или, что более важно, ошибку!).
Два извлеченных урока: НИКОГДА и ни при каких обстоятельствах не называйте таблицу после формы имени системы любой. Во-вторых, сначала нужно запустить операторы выбора, а затем изменить на удаление.
Между прочим, это был SqlServer 2005. Я все еще злюсь, что это не привело к ошибке.
В базе данных Access был запрос, подобный следующему:
SELECT *
FROM Bad_2 INNER JOIN Bad_1 ON Bad_2.Bad_1_id = Bad_1.ID;
и в обеих таблицах было поле с тем же именем. Когда Access встречает имя поля во второй раз, он создает для него новое имя. Предыдущий парень использовал сгенерированное имя поля в коде.
В свое время видел много прискорбных кусков SQL. Один, который приходит на ум, имеет форму
загружать данные из файла, перебирать этот файл, обращаясь к базе данных для каждой строки в файле.
Кажется нормальным в тестовых системах с 10 или около того строками, 100 000–1 миллион = неприятно даже для первичной ключевые поиски.
Кстати, решение состоит в том, чтобы загрузить данные в базу данных и думать наборами.
- Выберите свой любимый язык, например. perl, питон ...
загрузить файл в структуру данных (например, массив)
for (1 .. n) loop
myid := array[n];
select * from table where id = myid;
if the row exists update table set ... where id = myid;
end loop;
Худший ИСПОЛЬЗОВАТЬ SQL-запроса каждые:
Запрос SELECT, который подсчитывает количество строк, соответствующих определенному условию, вызываемый в условии остановки цикла for. Что-то вроде этого:
for(int i = 0; i < query("SELECT COUNT .... WHERE ..."); i++)
{
}
И нет, результат запроса не меняется на каждой итерации. Да, я понимаю, что сервер будет кэшировать результат.
В сообщении в группу новостей comp.databases.informix - настоящая рабочая таблица Informix (которую я не рекомендую использовать):
CREATE TABLE VIEW
(
DECIMAL CHAR(30),
NOT INTEGER NOT NULL,
SERIAL DATE NOT NULL,
NULL CHAR(1) NOT NULL,
INTEGER DECIMAL(13,6) NOT NULL
);
Помогает (незначительно), если вы знаете, что SERIAL - это тип в базах данных Informix - по сути, один из типов для последовательной генерации автоматически назначаемых номеров.
Мне понравился репостен недавно на dailywtf, история, которая идет с ним, тоже замечательна.
Хранимая процедура PL / SQL (Oracle), которая сортирует набор результатов с помощью Пузырьковая сортировка. Это было обнаружено, когда меня и администратора базы данных попросили выяснить серьезную проблему с производительностью. Разработчик, «эксперт» Oracle, работал над этим больше недели. Он объяснил с невозмутимым видом, что узнал о пузырьковой сортировке на уроке информатики. Алгоритм обычно используется для иллюстрации низкой производительности.
Заменил весь беспорядок предложением ORDER BY. Производительность улучшилась на несколько порядков.
Могут быть консультанты Oracle, которые не так уж и плохи, но я никогда их не встречал. Я работал с одной группой, чей «эксперт» по Oracle написал целую бухгалтерскую программу, используя «летучие» файлы, привязанные к ключам. Так, «I.bat» запускал форму счета-фактуры, «R.bat» - отчеты. Да, это было в конце 90-х.
Думаю, это худшее (особенно после болезненного и нулевого отката):
DROP DATABASE;
ROLLBACK;
SUBSTRING(
(SUBSTRING(LastName, 0, CHARINDEX(' ', LastName)) + ', ' + FirstName),
0,
CHARINDEX(' ', (SUBSTRING(LastName, 0, CHARINDEX(' ', LastName)) + ', ' +
FirstName), LEN(LastName) + 3)
)
Очевидно, они не были знакомы с RTRIM;
RTRIM(LastName) + ', ' + RTRIM(FirstName)
SELECT name FROM categories WHERE id IN (".implode(",",corrected_cats($ad->id)).") ORDER BY name ASC
Да, вы правильно прочитали ... поля в поле, разделенные запятыми.
Может, захотите сделать это сообществом WIKI, иначе кто-то его отключит.