Как найти пропуски sql

Пересказ статьи Brent Ozar. How to Find Missing Rows in a Table

Когда кто-то говорит: “Найдите все строки, которые был удалены”, – это много проще сделать, когда таблица имеет столбец identity (id). Давайте возьмем таблицу Users в базе данных Stack Overflow:

Имеются id: -1, 1, 2, 3, 4, 5…, но нет 6 или 7. (Или 0). Если кто-нибудь попросит вас найти все id, которые были удалены или пропущены, как это сделать?

Использование GENERATE_SERIES в SQL Server 2022 и новее

Новая функция GENERATE_SERIES делает то, о чем говорит ее название: генерирует последовательность чисел. Мы можем выполнить соединение таблицы Users с этой последовательностью, чтобы найти все значения последовательности, для которых нет совпадающих строк в таблице Users:

DECLARE @FirstId INT, @LastId INT;
SELECT @FirstId = MIN(Id),
@LastId = MAX(Id)
FROM dbo.Users;
SELECT gs.value
FROM GENERATE_SERIES(@FirstId, @LastId, 1) gs
LEFT OUTER JOIN dbo.Users u ON gs.value = u.Id
WHERE u.Id IS NULL;

Поначалу LEFT OUTER JOIN может вам показаться несколько неестественным, но работает отлично:

Что такое, спросите вы? Почему GENERATE_SERIES подчеркнуто красным? Ну, SQL Server Management Studio не обновилась синтаксисом T-SQL, который был в последнем релизе.

К счастью, Microsoft разделила установки приложений для SSMS и самого ядра SQL Server именно по этой причине – долгое время выпуска SSMS не позволяло команде разработчиков ядра ускорить выпуск, поэтому они поместили менее часто обновляемую SSMS в свой собственный установщик.

(Я правильно понял? Простите меня, если это не так.)

Использование таблицы чисел в более старых версиях

Если вы еще не работаете на SQL Server 2022, то можете создать собственную таблицу чисел, используя следующие примеры. Только убедитесь, что ваша таблица чисел содержит по крайней мере столько строк, сколько номеров id вы ищете. Вот пример с таблицей на 100000000 строк:

DROP TABLE IF EXISTS dbo.Numbers;
CREATE TABLE dbo.Numbers (Number INT PRIMARY KEY CLUSTERED);
INSERT INTO dbo.Numbers(Number)
SELECT TOP 10000000 row_number() over(order by t1.number) as N
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
CROSS JOIN master..spt_values t3
GO

Затем мы будем использовать это в том же ключе, что и GENERATE_SERIES:

DECLARE @FirstId INT, @LastId INT;
SELECT @FirstId = MIN(Id),
@LastId = MAX(Id)
FROM dbo.Users;
SELECT n.Number
FROM dbo.Numbers n
LEFT OUTER JOIN dbo.Users u ON n.Number = u.Id
WHERE u.Id IS NULL
AND n.Number > @FirstId
AND n.Number < @LastId
ORDER BY n.Number;

Это дает похожие результаты, но не идентичные:

В чем отличие? Да, этот метод не включает 0! Когда я наполнял мою таблицу чисел, то строил список только положительных целых. Единственной наиболее часто встречающейся мне ошибкой при использовании таблиц чисел является то, что они не охватывают всех необходимых нам чисел. Убедитесь, что они содержат как самое меньшее, так и самое большее из требуемых вам значений – проблема, которой мы не имеем с GENERATE_SERIES, поскольку там мы просто указываем начальное и конечное значения, а SQL Server делает все остальное.

Я не хочу погружаться глубже в другие способы решения этой проблемы, Itzik Ben-Gan введет вас в курс дела. Что до меня, мне нравится решать эту проблему быстро и легко с помощью GENERATE_SERIES. Кроме того, я ленив.

Время на прочтение
2 мин

Количество просмотров 32K

Разработчики и администраторы систем основанных на sql данных, наверняка, сталкивались с задачей — получить отсутствующее (пропущенное) значение в ряде id записей таблицы. Например номер договора, порядковый номер документа, телефонный номер, айпи-адрес и т.п. При работе с MySQL эта тривиальная задача непропорционально ресурсоемка.

Например, у нас есть пул внутренних телефонных номеров компании от 2001 до 2999 и таблица с выданными из них номерами для сотрудников:

  • t1.phone
  • 2001
  • 2002
  • 2003
  • 2004
  • 2005
  • 2009
  • 2015
  • 2016

Нам нужно найти первое свободное значение (в данном случае 2006) чтобы выделить очередной номер очередному сотруднику. Если свободных значений нет, то нужно выделить следующий из диапазона. Знакомая задача? Решения, которыми изобилует интернет, сводятся к двум принципам:

1) Делать перебор в цикле: например в SQL создать курсор CUR i+1 c 2001 до 2999 и делать запросы

SELECT t1.phone FROM t1 WHERE phone = i

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

2) Второй принцип, использовать LEFT (OUTER) JOIN последовательности 2001…2009 с таблицей t1 (WHERE t1.phone IS NULL конечно же), либо таблицы t1 с собой же со сдвигом на шаг:

SELECT MIN(t1.phone)+1 FROM t1 LEFT JOIN t1 AS diff ON (t1.phone = diff.phone+1) WHERE diff.phone IS NULL

Еще один вариант с использованием IN

SELECT ... WHERE phone NOT IN (....)

вообще не рассматриваю из-за громоздкости.

На маленьких объемах данных оба решения (и даже с IN) прекрасно работают, а при большом количестве записей эти решения либо ресурсоемки, либо продолжительны во времени, либо и то и другое.
Зависит от мощностей сервера и настроек базы, но в любом случае если перебирать миллион записей или приджойнить такую таблицу, даже на мощном сервере выполнение займет заметное время.

Я же захотел решить задачу быстро, не напрягая сервер, и, желательно, в один запрос. В один, не в один, но вот что получилось:


	/*выбираю граничные значения*/
	select 2000,2999 into @num,@maxid;

	select min(f.id) /* внешний селект дополнительный для "очистки" результата union */
	from
		(select s.num, min(s.num) /* первое расхождение рядов */ id
		from (
				select
					/* формирую ряд, в данном случае арифм.прогрессия, но может быть с любым шагом, или вычисляемым */
					@num:=@num+1 num,
					/* выбираю занятые значения */
					r.id 
				from t1 as r
				order by id
			) as s
		where 
			/* применяю условие расхождения рядов */ s.id != s.num /* причем ряды разойдутся и расхождение будет постоянным, поэтому во внешнем селекте использую только первое расхождение - min */
		/* если расхождения не было, добавляю еще одно возможное значение из диапазона граничных значений либо null, если значения закончились */
		union
		select @num+1 num, if(@num+1<@maxid,@num+1,null) id
		) as f
	where /* очищаю лишние результаты union */
		f.id is not null
	limit 1;

По сравнению с джойнами простые селекты выполняются в сотни раз быстрее.

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

UPD.
Прекрасное решение подсказал в личке участник stepmex
Без всякого дополнительного построения нумерации и сравнений рядов, изящно решил задачу через (SELECT 1 …..) IS NULL
Великолепная находка, я считаю:


SELECT (`t1`.`phone`+1) as `empty_phone`
FROM `t1`
WHERE (
	SELECT 1 FROM `t1` as `st` WHERE `st`.`phone` = (`t1`.`phone` + 1)
) IS NULL
ORDER BY `t1`.`phone`
LIMIT 1

i have a table of IDs and positions

CREATE TABLE #MissingSequence (ID INT NOT NULL, Position INT NOT NULL)
INSERT INTO #MissingSequence (ID,Position)
SELECT 36,1
UNION ALL SELECT 36,2
UNION ALL SELECT 36,3
UNION ALL SELECT 36,4
UNION ALL SELECT 36,5
UNION ALL SELECT 36,6
UNION ALL SELECT 44,1
UNION ALL SELECT 44,3
UNION ALL SELECT 44,4
UNION ALL SELECT 44,5
UNION ALL SELECT 44,6

What I am trying to find is if there is any break in the sequence of Positions by ID in this case the break between 44,1 and 44,3

I’ve managed to parse together:

SELECT  l.ID
    ,Start_Position = MIN(l.Position) + 1
    ,Stop_Position = MIN(fr.Position) - 1
FROM #MissingSequence l
LEFT JOIN #MissingSequence r 
    ON l.Position = r.Position - 1
LEFT JOIN #MissingSequence fr 
    ON l.Position < fr.Position
WHERE r.Position IS NULL
    AND fr.Position IS NOT NULL
GROUP BY l.ID

but it doesn’t work if there are multiple ID values. It does work if only a single ID, 44 exists.

thoughts, comments, suggestions?

thanks!

#1 12.05.2016 15:54:08

Сергей11
Участник
Зарегистрирован: 12.05.2016
Сообщений: 5

Как в таблице найти пропущенные строки

Можете кто-нибудь помочь написать запрос. Таблицы скачать можно тут. Нужно в таблице t1 в столбце ID_moi найти пропущенные значения. Для этого создал таблицу t1_copy в которой есть столбец ID_moi со всеми значениями по порядку. В таблице 1.5 мл строк и в будущем будет еще больше. Можно ли написать запрос так чтобы выполнялся не больше 1-2 часов?

Пробовал через таки  запрос:

SELECT t1_copy.ID_moi, t1.ID_moi
FROM t1_copy
LEFT JOIN t1
ON t1_copy.ID_moi = t1.ID_moi

Запрос почему-то выводит все совпадающие значения. Т.е должно по идее так:

6040    6040
6041    NULL
6042    6042
6044    NULL
6044    NULL
6045    6045

А получается что он строки где должно быть NULL просто пропускает и получается:

6040    6040
6042    6042
6045    6045

Если добавить в запрос какие-то уточнения типа WHERE и т.д., то такой запрос начинает выполняться вообще до бесконечности даже если поставить ограничение LIMIT 0, 5. Вообщем как вывести пропущенные значения так и не понял. Можете кто сможет подсказать? Спасибо.

Отредактированно Сергей11 (12.05.2016 15:59:06)

Неактивен

#2 12.05.2016 16:46:39

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

Сергей11 написал:

А получается что он строки где должно быть NULL просто пропускает и получается:

6040    6040
6042    6042
6045    6045

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

Сергей11 написал:

Если добавить в запрос какие-то уточнения типа WHERE и т.д., то такой запрос начинает выполняться вообще до бесконечности даже если поставить ограничение LIMIT 0, 5. Вообщем как вывести пропущенные значения так и не понял. Можете кто сможет подсказать? Спасибо.

SELECT t1_copy.ID_moi
FROM t1_copy
LEFT JOIN t1
ON t1_copy.ID_moi = t1.ID_moi
where t1.ID_moi is null;

в выложенных файлах не таблицы. сделайте дамп этих таблиц. Скорее всего там просто нет индексов. И зачем в таблице t1_copy колонка id?

Ещё можно решить вашу задачу через переменные, но сейчас нет базы под рукой, чтобы написать запрос.

Неактивен

#3 12.05.2016 18:46:06

Сергей11
Участник
Зарегистрирован: 12.05.2016
Сообщений: 5

Re: Как в таблице найти пропущенные строки

vasya написал:

результат большой, то возникает впечатление неверной работы.]

Точно. Только что сделал точно такие же таблицы, только строк поменьше. Этот запрос, который выше выводит почему-то строки с NULL в самый конец вот так:

6040 6040
6042 6042
6045 6045
6041 NULL
6044 NULL
6046 NULL

Соответственно если поставить лимит LIMIT 0, 20, то я так понимаю запрос до конца таблицы не доходит и строк с NULL не было видно.

vasya написал:

в выложенных файлах не таблицы. сделайте дамп этих таблиц.

vasya написал:

Скорее всего там просто нет индексов.

Есть индекс в основной таблит. (t1) на поле email для проверки уникальности. Еще какие-то индексы нужны?

vasya написал:

И зачем в таблице t1_copy колонка id?

Я пробовал все подрядят. Думал может проблема в том что нет столбца с ID. В принципе он не нужен ..можно удалить.

vasya написал:

Ещё можно решить вашу задачу через переменные, но сейчас нет базы под рукой, чтобы написать запрос.

Как время будет можете помочь написать. Очень нужно. Т.к. в таблицу планирую добавить очень много строк (до 1 миллиарда) и потом не хотелось бы ждать неделями выполнения любого запроса.

Вообще я думал MySQL быстро работает. Оказывается excel 2016 быстрее работает, но у него др. сложности.

Отредактированно Сергей11 (12.05.2016 18:53:46)

Неактивен

#4 12.05.2016 18:57:21

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

покажите вывод команд
show create table t1;
show create table t1_copy;

mysql работает быстро, вероятно у вас стоят минимальные дефолтные настройки.

Неактивен

#5 12.05.2016 20:09:16

Сергей11
Участник
Зарегистрирован: 12.05.2016
Сообщений: 5

Re: Как в таблице найти пропущенные строки

У меня MySQL стоит локально и я работаю через Navicat. Может быть это из-за него?

vasya написал:

покажите вывод команд
show create table t1;
show create table t1_copy;

Вот эти (show create table t1;)?

https://lh3.googleusercontent.com/73FhvlqcaWNFOybIdKD7S9j8ZG75zHGNuIWT0qlCyFMZgNvldkq5lGKswQAZEbnv72cAu1sZGZtxnEDlXkS0y7vWO24v56SFRwX272CHiWXre7ZGZjngq7UjfI-_HymPCcw1zU0QJ2OcFilj61GYVrFOtAOFFGdbm3Vt4IRmSDS4BQvRfvQXYZ6eNKmzGAsTI7YWtfRH6XWHljf24eRBJCpC1KWeoqmeBEujgwbFeLN9RSPfBxeeUrPl3WbmtMPK0TYfQ46I5CS_F5sYsPWLv3B6xhEA8GEyj0hgXySsZDcVIuW5bprEAzlIqsXZl5TJ6G0EVtWacW8xDqR4BBOU-TGlITiAVsZ4Q8Jm2svD5rDu8kuTpjx2XF0WyyLwM9P_TXKDpW5WWlwUPbTMBbrWjBGRDNy5E7rKgh-1Unl-DqO4tXdWMGj3DlUtGx_o7_8aqdcrZ5W1pYk_WUGZ9ItaGP-uM9TGBRk8zPftK39FccVfsYmQShWjq_cIetVigvwQC7cm_sfFhG5ILyAZo0CO5wxQl10Mp07-U7yUV7JIY0DRdYImFf0WfNRiVXNjLGfX7vywg6WRMLSBr08uC7B8npXMd7vClx8=w281-h124-no

https://lh3.googleusercontent.com/ZqikRvllR5U23WFynV8EAmkqTswoqbuVXfiRsExvpdou66ghgTsKqK5M74y2PFxV8BQL6h1AuKgJ-x74JsQnxycNSXlDWXSDQKvoCuW-aYZYqHVVEPXgy-Im0OlRi3DyLVuZFDrpbELCMDvN4s67r9AJcbZ_2_K7RF-VZR2z2bhbDah-CYfb61G5k3opxy3EjL2Zpi1n8pnBrDbUSEidcS6ZB8ChiI_UkfmL6vLy4VD85rGEqJ6nuyMD7XMdiYMDPp9GBgUYVc5GkSZx-YYq7utILMBIjrb98b-RJqQaJ03WL6pUmCbTZPSIfGKDkmwmTjdcyNfVQZBvhM-Jk1nErHwFd1k7h0eQYlc7Tg_JH1mlPauproqE8L1Qglhvgm1dItNzPGqmmria4mHDtiEKyNF8fth7A79davpxtwoFgraUpTBd6wN2sGRGs4bCwdeM3pnAzspRkZpTZw4DHBUwgm5ySkrQ-w0eeA8k5tuq0V4C7bldDVMPrIxYLab6SXhSgKIupdItRQbyOP21Ycd0dOYYPGnyfNd8_SyTowZzjbkD-FadXLfF-SjLAb9Lousfmtel0H2AdzycRmSIw36U8Jpd8W2rdM4=w313-h124-no

https://lh3.googleusercontent.com/rxoYd5YGMFI8W5jvlDZABqh6cum9_MO-I9yZoFNHCpWhNHu4UBYuE4pVZsWKe5StqTJmV4Kw9KOQn4wrj2jbIlbR3UfmdvGtX4INGACtK-sDHpLbDC1ME6_xKgEsibetxeJzKpiRx6HGzTzFtzgipYE8Tt_Y18kQbMbBYA3nJmDBeApSP5ihS45IhLzWOTpUi3nvWRFS8QI35YoKFcHO1IF9pJap77gMQf0n7cjYKL5HvsOADUmxw9KyE526PME0Keo_yzuflmKWsJuqSTLcFlD5ydqkjX2hC6ghd2b9SRxNNDV3rPWIa7ivss0CjWbcj-LYL3oE8xorNcjW5byIQhS0Gx5CdkVfzqHm6KPfUqVaFuat_CWSIke3rdU7JZaHRLWNhYV07u-1hKSw_aNO7I0gBjtNFOuy7ZtrbVNrSi8Y06VhmgTmQpIctdUPUdfp5Esr1PiJjBkFgtJloU6luzjMCxAxPBZmsmpg8FyIyWrcZnmmSUwqSgg6J565T8H3aF4HvCM9jLyuj6lj9sGK9gZwl_xY-MiAtlFeI1zkoGSGfPsR4CnacQeJYSOuh9GWhUrSf5_CqdFkYjVrGBTBCKcEEbbxKPI=w472-h216-no

https://lh3.googleusercontent.com/wIi_ReXXqfOg8UcLmILErX65jwSXa-kj0zPmtgXW8QVCM38pg6Rg5tpiLdrRuE3m7tis7g0F9q_R1d9yvUtbMQy7ae_jKsGcQT66TV4TW_OGsiQ4PM5OFQ0pKo-CfR0vAQ88TTVwdiiaf87G-dFLjgTrTHzW8SAmy5Oi7TBJa3morCHr5-mFQd9lyAVX2BpgJgvAJCVJHIF6ZGMS2rIlU7rs3FwcztIAo5x5P63ILn9OxGSX_IJ9-hN6NI6V8WwsMLmokOsXdnCbM9j4i2OilZ6r3SiaJl9a_k7hP9Q8GYhx8ABi6TDnueZ5B352pi8Wuy_pA5xV1Ychxg6Qves5gLfEwIpQYma0GZSKcNIJbAFvE188vB_oZbRRhKQhNAf2GEQ9vomn37x_W26rftk21DwrkNnIklsvcoa1UCUQjUw-6aIt8OzRiqeX-njWqZ8aC1cGZMNv20e2HuMyFcRwz513m5W5x5yt6vF9z87P5y2k4tFgzI01tGwKu0VwKGbpMILeGZakU-pSZsuOk8h-BqU6Wib-clQBit6knmPQ47kGMTf5I8hd8ycpxZFaLn20rXXiI0-o6xrvtiBqsgwLd5fRr5ecIWs=w807-h394-no

show create table t1_copy;

https://lh3.googleusercontent.com/ibdfnqV7k5Ake9zNSZfvlqtkzk4FZeICpkTcXxYKibUmQOiTG5ayB2fp2_BDXCBlSLyPArDAaCIxTUz0ZK4XS7uMtNieqrnnapLjNvSQFTbPB5zaLde3wlQWU7LEegEqHblhPwgnJedj6u9IwkyPi6G8o3VFbvSPoi_KI0XdyUHj-9gFxfj1nnAsa06uUXl_nBiJ4pj36KSNWpMEHYSteDxF-Nwm-3I0SY5DsWTjCWB45rwC4UYm-3Z6L57FMoKLWrDEuv-Evf3CPqdIxjCkmNOv7_KKiR8OTFW2aSWe0_T88W-m5PvMIWymlukgmaJxg5cg4yGtihJ7GcQu76zvzYCwqZZ6LSVaJ91ILBuHIan84OVdY81M8Ys278gE2hojcezVD0rLZ480Hjc3aXTACX7r3fxEGpe2VKUR3TeX_dLxLFjb_YuHkOfLopPXEz5N8ZrwKcW9h_p8a0CAWQjqIMJPat4M0hAbKWRRE_6rerQ1szbfodwf0utafWA5PzTCCUCZAwmhaRZyliwXEyDP8UVBF1DQ3kJzGt78vQsyEe4vTlpZ7W6Hy4xC-LQt7rTlNUvRpdJ8nvpRW5gU9C7clYcJLyQZkxA=w257-h123-no

https://lh3.googleusercontent.com/R07SsJHMMp9Kctx2cbZE4wSwvjpCK4xV6m0fofNpl7Mn7epV5Y10_NgzJwBnhXiuzVEQJFBBNclsz3Q_RHPte535pzWuDVq9JZCGN7fSuYzHVge92AkgUIXJq0lHWoi_0lVnH7RvBjhrLZg1VYIjrxw8go9mQcrEnpn8xSacXHWWCWPnlS_grz85TZU5K8u26Vk2EDSZKZ4kSYOJXCwPUyncI76cjkTDb8Wol3I21WQLp6hBWsEKyquQUcMPTP9fr5MtBk6qKYWSCYJKi9XvJ4JFHUS9XER7tOhYUEKfTpxemqZxj1KDOgfBIfh4ccAlGT8Wkab1-OIZso9QLyl9RvmLdtBuppktlTLoA_JkCfASPEB72RQRZbsA9tKvb3jUBHS4QRR-7fgKjMtlCjlg48JSo_7IaUHlCZxlCkouNniaUvpxdvq7No2Pipf9a4-6vfMIqkxxoOw1kKiIA94Z1K2PZj-hiVN9DHL4ztT_S0ZfpgyfhW6B_sdNFSt6e7nxOlnBWgJ10D8eOKF_6IG8OHDThSJvjhpCpu8WpdmefrCY_Ock_FVBXm307XwUTlNg1JIxp0xcqKZm1HRqfDEsHuh8JGsJWu8=w266-h99-no

https://lh3.googleusercontent.com/EaUrlWlx1uhaMeQGw7V3CU0zUFE2IqXWQDNPXDeeNi6exg6Zo7v8QBz-m7_rhR_J93DD-px0u-SyXhVT0d9nc3rzB76sv9Odxz6UURSQa8Uuiv4h19KVPrTZj2MIGgvkVNfzl3XUWMlv0Kw_Zp3jjXZUmxJpLurYJF5lXSMFEmZxIP6GHOtJocd3zCW7pSbwBcuRi5q6v2efR8bFv3DgURAz229eEeeaD-1RYPFIWs83BGaIFD_K6cPKHyeKuIx6391EtUZIeQieC_BD5MC8jBn5-7OovxqfeREtW-O3qbiwyoHWOMp_v89pjQFQTP5OPFBoPtFW1Zr5Lw4FPh6DBMMefXa-8MeIYH33WxgUxbxJDeF0S-yIbdkHxqWacrcE9I4NOhu-tWIkVbPhZDykZ6Nneu3GOua6A_0WW-MW36JMdm4ObtWmlvbI9BggBcK4eeg4RlIDPGiiHVvEjjolrrWrDhZR71wpoyG3_oUsWWJhiZxs4IuqFmy9CxMZ-7ZcSFk57TP7HXbMsucdy8HWdSYkcNFMwSKg-2ALrq10DX0a5KAfyt13rYgtnTnqTut2aAzGGEEtlO93N3p7l0PKMdHlxyBvyUs=w483-h223-no

https://lh3.googleusercontent.com/HraB1b6cEzcg54ttbmU2PEc8SnzdpGzD6i8LMJoaXxA_K3jlDTv8Qznk97JXuZusIqz-ZUVNfK1ShcCu082uvuV7SDiSo-t_mD-w4frVP4HtO1qPPzb3YQEt8bcpRutFqH049OLMRt1If6ecZJE5ElXueUQpfp1iDv2X8lnXJcdO4yY8q_yZdy26Uvf1rQm3ECUb4yijTWBcGUnvwsCtelPokNBperw33aiysg_kNRRa_i12z2SnDEZsK4FE7nFmVAZLjw0MlfsJ_xyD_NDSpKihvRAXxvuSBG6c2ceItc-AAkEaYleYm4wuHNSDaXLfL29o3o6RAnQBzhkIjvu9RqKCbeRRJ5xKIU8QuAANqGXFNqyTotF5uaT5hyU7pBoJInKuIyEbL51PMjSrps8oXi65KG2gfpKLHho7tLIrq04YLgx4ELfcHsmTvpjpjeBJRlHoXibqOg-Arwe7Q3tMGG9Dua69P87uOcJhGxIKiwO13nMX-txC9ZbzyHAKyPP-y0EryhYtGHFLUskxZ1vBk1_O5ullFjUaAfz4EC6fb-jqWPVsQOqUqCDuHjfcMnaB8mxNmTHNzAoqgLklK7QVI4x5VNDo1Ts=w801-h387-no

vasya написал:

mysql работает быстро, вероятно у вас стоят минимальные дефолтные настройки.

Запрос на объединение 2 таблиц с 1.5мл строк (запрос который выше) сколько примерно должен выполняться?

Неактивен

#6 12.05.2016 20:31:41

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

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

Неактивен

#7 12.05.2016 21:07:40

Сергей11
Участник
Зарегистрирован: 12.05.2016
Сообщений: 5

Re: Как в таблице найти пропущенные строки

vasya написал:

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

Вот так:

show create table t1;

https://lh3.googleusercontent.com/AtF6SpaCqh_nRlTFAfhwUut1NhM_fAut6jtnsOkHRJpiTEldJwwf5Cg6dPsrhmSE16joO_3YcvXzmz3_LK1d6MVqOahmq5y52jRff55idDRD_nf_egxtNJjmHhhEvrVUDKz5S3KuOrFR0r50xkEDbH9yuha3SKwvp496t9HZrNd8rnMOLvMqWTDjV3uyFaVTmI25yVeF3MhnBteja4qeXYlakZ2HZci4BjvaHqWy-9xVm8hhXXB4C5jQggrGjyP2fHeU7_EYKKBEiJ5JI0hevi6obrb4vCYN9drMUGypvD8zchPS4dIXR-LykpMkJDMAizuWC69PJ-Z3TNMNV3m0wmPPK8xx_vRFShlJjlC7iG0rgsJ-PxMxiFmoXEJVenc2dSocAcP2yoHaYs2zs0_ry4YSJY9-zW92Tmzlr5tH6txfzuxq-l-Igj0Byoo9B3jdSg6owyAw70VAzyhlfwdib2DEKdZgfau3gqhfl3UgSzKZxX8qk5rx52zhhtnMs5xflf2KNag2yXTjZOHQVUueNQuTGJfOyP1RanT_37wtNLY9zf9GztyElJ6gwCfTfY8_sraB7lwf98XCUNHQJ4cl9AjO0BMlCRw=w565-h379-no

show create table t1_copy;

https://lh3.googleusercontent.com/JbgOrtLeDo3P23QPHOoNfrEolrPy6hg7eg9njsbtiEyljNv_DEIcWDpNTa8OqQdXVCZieMP-2yWlSGWkgLz-2SeiAvNJ_Ii4a9eDbNR1EIL8ohVAYnW3GqaGTPe2Xuhx-KhRtTDoC2BT8kgAyqXG5BiPM5DcqudBCW6kzPH4GcVqtWu7uLyLTa5vgVuo7IkAtXT1v0_CetHfLTvWZyOwt12wjh81OPBEI7i2DosmMcBu3okgjbD9ilKAzLUIbchRyLG8OPCf7-IM4a6wIsK7DlVOSsZ3DeCpPAM0t5RLFqbQ2oZdX1iUFZi1hoLI0OAEa-nfbIUzHGqSDZWRDqYje93yBx0CF3gYWmK40dRD8a2im5SM8y8T4flPuRdczoGERdamHQxSa7gMzC2KVHDNSMpWR1hPsys0CJrgu_pZiGAbXOi9eXQDjcIci_Aj4sgeGUvdMyRQUpkkTYqGCeafTwCmRDtyZllLIhsQVR3CrN6HymXMCqpljeJynuqEbmT7AuH5QIU4easpaMrSz7bse0zdqYERDPJFwylPKjxn-7UXmyWxSCSWy1-oyrwnxx6P8LQkGTMkdoPI1Fx8PxAzVerDl9kq7f8=w639-h291-no

Неактивен

#8 12.05.2016 21:16:17

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

id_moi уникальный?
alter table t1 add unique (id_moi);

а почему он varchar(255) а не int?

Неактивен

#9 12.05.2016 21:16:53

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

ну и в t1_copy оставить только id_moi

Неактивен

#10 12.05.2016 21:20:13

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

create table t1_copy (id_moi int not null primary key);

в таблице t1:
поле id_moi может принимать null? (аналогично name, lname)
id нужно?

Неактивен

#11 12.05.2016 21:40:21

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5817

Re: Как в таблице найти пропущенные строки

Резумируя, вам нужно сделать, как минимум:

alter table t1 modify id_moi int not null;
alter table t1 add unique (id_moi);
alter table t1_copy drop `key`;
alter table t1_copy modify id_moi int not null auto_increment primary key;

после чего проверить скорость выполнения запроса.

Неактивен

#12 12.05.2016 23:52:55

Сергей11
Участник
Зарегистрирован: 12.05.2016
Сообщений: 5

Re: Как в таблице найти пропущенные строки

vasya написал:

Резумируя, вам нужно сделать, как минимум:

alter table t1 modify id_moi int not null;
alter table t1 add unique (id_moi);
alter table t1_copy drop `key`;
alter table t1_copy modify id_moi int not null auto_increment primary key;

после чего проверить скорость выполнения запроса.

Спасибо большое что так подробно написали. Вроде разобрался. Теперь запрос выполняется за 18 сек.

Неактивен


[Oracle] Поиск пропусков в последовательности

От:

anonymous

Россия

http://denis.ibaev.name/
Дата:  11.10.06 13:06
Оценка:

В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.


Re: [Oracle] Поиск пропусков в последовательности

От:

Lloyd

Россия

 
Дата:  11.10.06 13:24
Оценка:

:)

Здравствуйте, anonymous, Вы писали:

A>В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.

select Id
from table t1
where not exists(select * from table t2 where t2.Id = t1.Id)

… << RSDN@Home 1.1.4 stable SR1 rev. 568>>


Re[2]: [Oracle] Поиск пропусков в последовательности

От:

Alex.Che

 
Дата:  11.10.06 13:26
Оценка:

Привет, Lloyd!
Вы пишешь 11 октября 2006:

L>

select Id
from table t1
where not exists(select * from table t2 where t2.Id = t1.Id)

Полный аут!


With best regards, Alex Cherednichenko.

Posted via RSDN NNTP Server 2.0


Re: [Oracle] Поиск пропусков в последовательности

От:

Softwarer

http://softwarer.ru
Дата:  11.10.06 13:36
Оценка:

14 (1)

Здравствуйте, anonymous, Вы писали:

A>В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.

Например,

with
  d1 as (select 1 id from dual union all select 2 from dual union all select 3 from dual union all select 5 from dual union all select 6 from dual),
  d2 as (select id, lead (id) over (order by id) next_id from d1),
  d3 as (select id + 1 missed_id from d2 where id <> next_id - 1 order by id)
select
  *
from 
  d3
where
  rownum <= 1


Re: [Oracle] Поиск пропусков в последовательности

От:

bloom

 
Дата:  11.10.06 13:40
Оценка:

7 (1)

Здравствуйте, anonymous, Вы писали:

A>В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.

это ?

  SELECT coalesce(MIN(CASE WHEN num <> rn THEN rn END), MAX(num) + 1, 1)
    FROM (SELECT num, row_number() over(ORDER BY num) AS rn FROM t)


Re: [Oracle] Поиск пропусков в последовательности

От:

wildwind

Россия

 
Дата:  11.10.06 13:51
Оценка:

38 (2)

Здравствуйте, anonymous, Вы писали:

A>В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.

Например так:

with t as (
  select 1 n from dual union all
  select 2 from dual union all
  select 3 from dual union all
  select 5 from dual union all
  select 6 from dual
)
select n+1 miss from (
select n, lead(n) over (order by N) - n diff
  from T order by n
)
 where diff > 1 and rownum <= 1


Re: [Oracle] Поиск пропусков в последовательности

От:

_Oleg_

Украина

 
Дата:  11.10.06 13:53
Оценка:

7 (1)

Здравствуйте, anonymous, Вы писали:

A>В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.

На основе:

select t.id,
       (select count(*)
        from table1 t1_
        where t1_.id <= t.id
       ) c
from table1 t
order by t.id

…что-то вроде:

select q.*
from
(select t.id,
        (select count(*)
         from table1 t1_
         where t1_.id <= t.id
        ) c
 from table1 t
 order by t.id
) q
where q.c <> q.id


Re: [Oracle] Поиск пропусков в последовательности

От:

anonymous

Россия

http://denis.ibaev.name/
Дата:  11.10.06 14:02
Оценка:

Здравствуйте, anonymous, Вы писали:

A>В столбце таблицы хранятся некоторые целочеисленные значения. Как я могу найти первое пропущенное значение в последовательноти образованной сортировкой значений из таблицы по возрастанию? Например, для последовательности 1, 2, 3, 5, 6 это будет 4.

В общем, подумав, сделал сам:

  SELECT min(t.id) + 1
    FROM tbl t 
    WHERE (
      SELECT id
        FROM tbl
        WHERE id = t.id + 1 ) IS NULL


Re[3]: [Oracle] Поиск пропусков в последовательности

От:

Lloyd

Россия

 
Дата:  11.10.06 14:22
Оценка:

Здравствуйте, Alex.Che, Вы писали:

AC>Полный аут!


AC>–

AC>With best regards, Alex Cherednichenko.

Поясни

… << RSDN@Home 1.1.4 stable SR1 rev. 568>>


Re[4]: [Oracle] Поиск пропусков в последовательности

От:

Alex.Che

 
Дата:  11.10.06 14:35
Оценка:

Привет, Lloyd!
Вы пишешь 11 октября 2006:

AC>> Полный аут!


L> Поясни

Зачем?
Все и так всё поняли

ЗЫ: Если не понимаешь, погоняй свой запрос на тестовых данных.


With best regards, Alex Cherednichenko.

Posted via RSDN NNTP Server 2.0


Re[2]: [Oracle] Поиск пропусков в последовательности

От:

wildwind

Россия

 
Дата:  11.10.06 14:38
Оценка:

7 (1)

Здравствуйте, anonymous, Вы писали:

A>В общем, подумав, сделал сам:

A>

A>  SELECT min(t.id) + 1
A>    FROM tbl t 
A>    WHERE (
A>      SELECT id
A>        FROM tbl
A>        WHERE id = t.id + 1 ) IS NULL
A>

Если таблица большая, может быть не очень эффективно. Подумай все же об аналитике.


Re[5]: [Oracle] Поиск пропусков в последовательности

От:

Lloyd

Россия

 
Дата:  11.10.06 14:43
Оценка:

7 (1)

Здравствуйте, Alex.Che, Вы писали:

AC>Зачем?

AC>Все и так всё поняли

AC>ЗЫ: Если не понимаешь, погоняй свой запрос на тестовых данных.

Все, дошло.

Имелось в виду следущее:

select Id
from table t1
where not exists(select * from table t2 where t2.Id = t1.Id + 1)

… << RSDN@Home 1.1.4 stable SR1 rev. 568>>


Re[3]: [Oracle] Поиск пропусков в последовательности

От:

anonymous

Россия

http://denis.ibaev.name/
Дата:  11.10.06 15:16
Оценка:

Здравствуйте, wildwind, Вы писали:

W>Если таблица большая, может быть не очень эффективно. Подумай все же об аналитике.

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


Re[2]: [Oracle] Поиск пропусков в последовательности

От:

anonymous

Россия

http://denis.ibaev.name/
Дата:  11.10.06 15:38
Оценка:

Здравствуйте, bloom, Вы писали:

B>это ?

B>

B>  SELECT coalesce(MIN(CASE WHEN num <> rn THEN rn END), MAX(num) + 1, 1)
B>    FROM (SELECT num, row_number() over(ORDER BY num) AS rn FROM t)
B>

Скорее так:

SELECT MAX(CASE WHEN num = rn - 1 THEN num END)
  FROM (SELECT num, row_number() over(ORDER BY num) AS rn FROM t)


Re[4]: [Oracle] Поиск пропусков в последовательности

От:

Igor Trofimov

 
Дата:  11.10.06 17:33
Оценка:

A>Да, действительно медленно. Придется теперь как-то выбирать из предложенных вариантов. )

Или еще раз подумать, а для чего тебе это надо


Re[3]: [Oracle] Поиск пропусков в последовательности

От:

bloom

 
Дата:  12.10.06 06:45
Оценка:

7 (1)

Здравствуйте, anonymous, Вы писали:

A>Здравствуйте, bloom, Вы писали:


B>>это ?

B>>

B>>  SELECT coalesce(MIN(CASE WHEN num <> rn THEN rn END), MAX(num) + 1, 1)
B>>    FROM (SELECT num, row_number() over(ORDER BY num) AS rn FROM t)
B>>



A>Скорее так:

A>

A>SELECT MAX(CASE WHEN num = rn - 1 THEN num END)
A>  FROM (SELECT num, row_number() over(ORDER BY num) AS rn FROM t)
A>

да не

CASE WHEN num = rn - 1 THEN num END

не обеспечит желаемого результата (для прмера набор 1,2,4), да и MAX — даст не первый пропуск

ЗЫ ну разве что MAX(num) + 1 — посколкьу это для случая когда пропусков нет вообще


Re[5]: [Oracle] Поиск пропусков в последовательности

От:

anonymous

Россия

http://denis.ibaev.name/
Дата:  12.10.06 07:49
Оценка:

Здравствуйте, Igor Trofimov, Вы писали:

A>>Да, действительно медленно. Придется теперь как-то выбирать из предложенных вариантов. )

iT>Или еще раз подумать, а для чего тебе это надо

Ну это я точно знаю. Попробую обяснить на прмере. Пусть есть последовательность 1, 2, 3, 5, 6, 7, мне нужно вставить в неё значение 2, но значения дублироваться не должны, поэтому предварительно нужно увеличить 2 и 3 из последовательности на 1. Так вот, чтобы знать какие из значений увеличивать, мне и нужен этот запрос. Иначе пришлось бы увеличивать все значения с 2 до 7.


Re[6]: [Oracle] Поиск пропусков в последовательности

От:

Lloyd

Россия

 
Дата:  12.10.06 08:07
Оценка:

Здравствуйте, anonymous, Вы писали:

A>Ну это я точно знаю. Попробую обяснить на прмере. Пусть есть последовательность 1, 2, 3, 5, 6, 7, мне нужно вставить в неё значение 2, но значения дублироваться не должны, поэтому предварительно нужно увеличить 2 и 3 из последовательности на 1. Так вот, чтобы знать какие из значений увеличивать, мне и нужен этот запрос. Иначе пришлось бы увеличивать все значения с 2 до 7.

А для чего если не секрет? Уж не для упорядочивания ли?

… << RSDN@Home 1.1.4 stable SR1 rev. 568>>


Re[7]: [Oracle] Поиск пропусков в последовательности

От:

anonymous

Россия

http://denis.ibaev.name/
Дата:  12.10.06 08:22
Оценка:

Здравствуйте, Lloyd, Вы писали:

A>>Ну это я точно знаю. Попробую обяснить на прмере. Пусть есть последовательность 1, 2, 3, 5, 6, 7, мне нужно вставить в неё значение 2, но значения дублироваться не должны, поэтому предварительно нужно увеличить 2 и 3 из последовательности на 1. Так вот, чтобы знать какие из значений увеличивать, мне и нужен этот запрос. Иначе пришлось бы увеличивать все значения с 2 до 7.

L>А для чего если не секрет? Уж не для упорядочивания ли?

Для него.


Re[8]: [Oracle] Поиск пропусков в последовательности

От:

Lloyd

Россия

 
Дата:  12.10.06 08:26
Оценка:

12 (3)

Здравствуйте, anonymous, Вы писали:

L>>А для чего если не секрет? Уж не для упорядочивания ли?


A>Для него.

Я в одном продукте подсмотрел очень интересное решение для упорядочивания. Там в при первоначальной вставке порядковые номера писались как обычно 1, 2, 3, …, но тип был не целочисленный, а с плавающей точкой. Если впоследствии возникала необходимость добавить новыю запись между двумя существующими, то использовали среднее от соседних порядковых номеров. Посмотри, возможно и тебе этот вариант подойдет.

… << RSDN@Home 1.1.4 stable SR1 rev. 568>>

Подождите ...

Wait...

  • Переместить
  • Удалить
  • Выделить ветку

Пока на собственное сообщение не было ответов, его можно удалить.

Добавить комментарий