как в запросе найти дырку в последовательности чисел? |
Я |
13.12.17 — 18:36
Есть коды весовых товаров, оказывается весы имеют ограничение 5200 кодов. Вот автоматическая назначалка кодов уперлась в этот потолок. Что то мне не верится, что нету дырок, хочу переделать назначалку, что бы брала первый свободный код до 5200
1 — 13.12.17 — 18:38
Отсортируй и считай разницу. PLU не хватает? Дроби по отделам.
2 — 13.12.17 — 18:39
ну соедини с табличкой цифр и сгруппируй, там где Имеющие сумма =1 и есть «дырка»
3 — 13.12.17 — 18:42
(2) О хорошая идея.
(1) Про отделы спасибо, подумаем, хотя немного проблематично, так как весы одни или 2-я, а они ломаются часто. Ненадежная техника. И тогда используют одни.
4 — 13.12.17 — 18:43
(0) Перенумерация не подходит?
5 — 13.12.17 — 18:44
(4) Не это исключено, коды PLU не могут меняться.
А как можно создать табличку цифр если не использовать цикл?
6 — 13.12.17 — 18:45
(0) Решать такого рода задачи запросом — извращение.
Но если уж очень хочется, тогда:
1 соединяешь таблицу с самой собой по условию т2.код<т1.код.
2. группируешь по т1.код и агрегируешь МАКСИМУМ(т2.код)
3. накладываешь условие т1.код-т2.код>1
7 — 13.12.17 — 18:46
(5) выбрать 1
объединить
выбрать 2
объединить
выбрать 3…
и т.д.
8 — 13.12.17 — 18:53
Выгрузить в Эксель, добавить колонку с «правильным» кодом, прописать его последовательными значениями, посмотреть разницу.
9 — 13.12.17 — 18:54
10 — 13.12.17 — 18:55
Ну или так,
SELECT
(a3.id + a2.id + a1.id + a0.id) КАК Числа
FROM
(
SELECT 1 id UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9
) as a0
INNER JOIN
(
SELECT 0 id UNION ALL
SELECT 10 UNION ALL
SELECT 20 UNION ALL
SELECT 30 UNION ALL
SELECT 40 UNION ALL
SELECT 50 UNION ALL
SELECT 60 UNION ALL
SELECT 70 UNION ALL
SELECT 80 UNION ALL
SELECT 90
) as a1 ON TRUE
INNER JOIN
(
SELECT 0 id UNION ALL
SELECT 100 UNION ALL
SELECT 200 UNION ALL
SELECT 300 UNION ALL
SELECT 400 UNION ALL
SELECT 500 UNION ALL
SELECT 600 UNION ALL
SELECT 700 UNION ALL
SELECT 800 UNION ALL
SELECT 900
) as a2 ON TRUE
INNER JOIN
(
SELECT 0 id UNION ALL
SELECT 1000 UNION ALL
SELECT 2000 UNION ALL
SELECT 3000 UNION ALL
SELECT 4000 UNION ALL
SELECT 5000 UNION ALL
SELECT 6000 UNION ALL
SELECT 7000 UNION ALL
SELECT 8000 UNION ALL
SELECT 9000
) as a3 ON TRUE
ORDER BY Числа
11 — 13.12.17 — 18:57
(10) А INNER JOIN зачем пишете?
12 — 13.12.17 — 18:59
(9) (10) фу
13 — 13.12.17 — 19:01
(11) да пофик, там обычный cross join
14 — 13.12.17 — 19:02
SELECT
(a3.id + a2.id + a1.id + a0.id) КАК Числа
FROM
(
SELECT 1 id UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9
) as a0 ,
(
SELECT 0 id UNION ALL
SELECT 10 UNION ALL
SELECT 20 UNION ALL
SELECT 30 UNION ALL
SELECT 40 UNION ALL
SELECT 50 UNION ALL
SELECT 60 UNION ALL
SELECT 70 UNION ALL
SELECT 80 UNION ALL
SELECT 90
) as a1
,
(
SELECT 0 id UNION ALL
SELECT 100 UNION ALL
SELECT 200 UNION ALL
SELECT 300 UNION ALL
SELECT 400 UNION ALL
SELECT 500 UNION ALL
SELECT 600 UNION ALL
SELECT 700 UNION ALL
SELECT 800 UNION ALL
SELECT 900
) as a2
,
(
SELECT 0 id UNION ALL
SELECT 1000 UNION ALL
SELECT 2000 UNION ALL
SELECT 3000 UNION ALL
SELECT 4000 UNION ALL
SELECT 5000 UNION ALL
SELECT 6000 UNION ALL
SELECT 7000 UNION ALL
SELECT 8000 UNION ALL
SELECT 9000
) as a3
ORDER BY Числа
15 — 13.12.17 — 19:03
(12) Предложи альтернативу.
16 — 13.12.17 — 19:06
(15) В (6) альтернатива. Запрос будет в несколько раз короче, а работать при 5200 позициях все будут быстро.
17 — 13.12.17 — 19:10
(16) не понял, как при inner join + max, для таблицы из 2-х элементов по твоему алгоритму
1
10
ты найдешь 2,3,4,5,6,7,8,9 ?
18 — 13.12.17 — 19:34
(17) Ты наёдешь первую дырку, следующее число в которой — свободно.
19 — 13.12.17 — 19:42
(18) задача то, все найти, насколько я понял, а не первую
20 — 13.12.17 — 19:42
(19) «хочу переделать назначалку, что бы брала первый свободный код до 5200»
21 — 13.12.17 — 20:05
какие у вас весы?
в весах есть записи 5200,а есть коды плу-их обычно 99999,т.к.на код 5 символов,если работатт в кодах,то нужно всего лишь,чтобы в весы грузились не более 5200 товаров,и в разные весы можно грузить разные товары
22 — 13.12.17 — 20:07
а так,соединение таблицы сама с собой со смещкнием 1 и отсортировать по знаяению и выбрать первый,где значение второй соедмненной таблицы Null
23 — 13.12.17 — 21:04
Генерировать здесь таблицу чисел как предлагается в (2) совершенно не нужно, так же как и искать интервалы как предлагается в (6). Это существенно дольше и в данном случае совершенно излишне. Решать такие задачи запросом можно и нужно. Это гораздо быстрее, чем другими способами.
Поддержу (22), но с замечанием, что лучше не соединять, а объединять примерно как в в задаче 30 из http://catalog.mista.ru/public/460935/
ВЫБРАТЬ Х, ЛОЖЬ КАК Свободен ПОМЕСТИТЬ ЧислаПлюс ИЗ Числа ОБЪЕДИНИТЬ ВЫБРАТЬ Х + 1, ИСТИНА ИЗ Числа ; ВЫБРАТЬ ПЕРВЫЕ 1 Х КАК ПервыйСвободныйАртикул ИЗ ЧислаПлюс СГРУППИРОВАТЬ ПО Х ИМЕЮЩИЕ КОЛИЧЕСТВО(*) = 1 И МАКСИМУМ(Свободен) = ИСТИНА
Если коды строковые, а не числовые, то нужно взять из 30 все решение целиком, с преобразованием строк в числа.
24 — 13.12.17 — 21:26
Коды числовые? Тогда вот:
ВЫБРАТЬ ПЕРВЫЕ 1 Табличка1.Код + 1 КАК Код ИЗ Табличка КАК Табличка1 ЛЕВОЕ СОЕДИНЕНИЕ Табличка КАК Табличка2 ПО (Табличка1.Код + 1 = Табличка2.Код) ГДЕ Табличка2.Код ЕСТЬ NULL
25 — 13.12.17 — 21:27
УПОРЯДОЧИТЬ ПО
Табличка1.Код
26 — 13.12.17 — 21:36
(24) При отсутствии индекса по Код такое соединение приведет к перебору всех элементов «Табличка2» для каждого элемента «Табличка1». Значит, будет квадратичный рост. Если в табличке 10 000 элементов, то произведение уже 100 миллионов. Это уже больше сотни секунд — многовато для такой задачи. Решение (23) свободно от такого недостатка. В нем зависимость линейная. Выполнится за сотые-десятые доли секунды.
27 — 13.12.17 — 21:41
(26) Согласен, без индекса будет долго. Но всякие коды чаще всего проиндексированы.
28 — 13.12.17 — 22:15
(26) тогда выгружаем с индексированием во временную таблицу и радуемся
29 — 13.12.17 — 22:16
хотя,перебор все равно светит,поэтому просто перебираем ьаблицу и ищем первую ячейку,где код не соответствует номеру
30 — 13.12.17 — 22:30
Ради интереса запилил тестовую обработку, 10000 строк, ну и замер производительности на моем тарантасе:
Без индексирования в цикле 10 раз (больше не рискнул из-за 100 млн.):
23 за 0,764693 сек,
24 за 26,450973 сек — ожидаемо долго.
Первый вариант рвет мой на мелкие части )
С индексированием в цикле 1000 раз:
23 за 28,047738 сек
24 за 2,526163 сек
А вот тут индексы уже рулят, вариант в 23 проигрывает из за группировки и поиска максимумов.
31 — 13.12.17 — 22:51
(30) в (22) была неточность, попробуйте ОБЪЕДИНИТЬ ВСЕ и без временной таблицы. Вот в таком виде:
; ВЫБРАТЬ ПЕРВЫЕ 1 Х КАК ПервыйСвободныйАртикул ИЗ (ВЫБРАТЬ Х, ЛОЖЬ КАК Свободен ИЗ Числа ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ Х + 1, ИСТИНА ИЗ Числа) КАК ВложенныйЗапрос СГРУППИРОВАТЬ ПО Х ИМЕЮЩИЕ КОЛИЧЕСТВО(*) = 1 И МАКСИМУМ(Свободен) = ИСТИНА
Проигрыш должен быть, но не такой существенный. Похоже больше не на потери на вычислениях, а на потери времени на запись временной таблицы.
32 — 13.12.17 — 23:26
Есть еще вариант
ВЫБРАТЬ ПЕРВЫЕ 1 Дано.Х + ВЗ.У КАК Х ИЗ Дано КАК Дано, (ВЫБРАТЬ 0 КАК У ОБЪЕДИНИТЬ ВЫБРАТЬ 1) КАК ВЗ СГРУППИРОВАТЬ ПО Дано.Х + ВЗ.У ИМЕЮЩИЕ КОЛИЧЕСТВО(*) = 1 И МИНИМУМ(ВЗ.У) = 1 УПОРЯДОЧИТЬ ПО Дано.Х + ВЗ.У
33 — 13.12.17 — 23:59
+(32) А можно еще ВЫБРАТЬ ПЕРВЫЕ 2 и МИНИМУМ(ВЗ.У) = 1 не проверять. В общем, простор для исследований есть))
34 — 14.12.17 — 00:35
(33) Пока Вы здесь… ))
На сколько криво так писать? — на листике накидано по-быстренькому:
«ВЫБРАТЬ
Справ.Код
ПОМЕСТИТЬ Справ
ИЗ
Справочник.НекийСправочник КАК Справ
;
Выбрать
Справ1.Код,
ЕСТЬNULL(Справ2.Код, Справ1.Код) КАК КодПредыдущий
ИЗ
Справ КАК Справ1
ЛЕВОЕ СОЕДИНЕНИЕ Справ КАК Справ2
ПО Справ2.Код В
(ВЫБРАТЬ //* можно ПЕРВЫЕ 1 без МАКСИМУМ, при этом УПОРЯДОЧИТЬ ПО СправПров.Код УБЫВ *//
МАКСИМУМ(СправПров.Код)
ИЗ
Справ КАК СправПров
ГДЕ
СправПров.Код < Справ1.Код)
ГДЕ
Справ1.Код — ЕСТЬNULL(Справ2.Код, Справ1.Код)>1
;
УНИЧТОЖИТЬ Справ»
35 — 14.12.17 — 00:55
(34) Это кореллированный запрос. В условиях соединения его использовать не рекомендуется. Если индекс по полю код есть, то можно робко надеяться на хороший план запроса, где агрегатная функция будет браться из индекса и соединение будет на него же опираться, но гораздо чаще бывает по другому. В файловой базе и Postgre точно будут тормоза, а в MSSQL возможно будут. Я бы не рисковал, если есть более надежные способы.
36 — 14.12.17 — 01:09
(35) Спасибо!
37 — 14.12.17 — 16:32
(31) Проверил
31 за 11,609783 сек
24 за 1,627492 сек
ну, это один из результатов, гонял несколько раз, порядок значений тот же.
Но 31 действительно надежнее в любых условиях, да и пользователь при интерактивной работе разницы не заметит.
38 — 14.12.17 — 17:10
(37) Спасибо, согласен, но раз «пошла такая пьянка», не проверите еще (32)+(33). Там другой подход. Лучше в виде:
ВЫБРАТЬ ПЕРВЫЕ 2 Дано.Х + ВЗ.У КАК Х ИЗ Дано КАК Дано, (ВЫБРАТЬ 0 КАК У ОБЪЕДИНИТЬ ВЫБРАТЬ 1) КАК ВЗ СГРУППИРОВАТЬ ПО Дано.Х + ВЗ.У ИМЕЮЩИЕ КОЛИЧЕСТВО(*) = 1 УПОРЯДОЧИТЬ ПО Дано.Х + ВЗ.У
39 — 15.12.17 — 11:06
(38)
В цикле 1000 раз:
32 13,264319
33 16,620937 — интересно тем, что выдает диапазон кодов, между которым есть пропуски, т.е. последний имеющийся до и первый после пропуска. Части ПОМЕСТИТЬ и УНИЧТОЖИТЬ из запроса выбросил, так как на вход всех тестируемых запросов и так подается ранее сформированная тестовая табличка с кодами, т.е. осталась только работающая часть запроса.
37 11,977468 — в первой строке всегда 0, во второй нужное значение
Ildarovich
40 — 15.12.17 — 13:41
(39) Большое спасибо!
Как найти «дыры» в таблице
Недавно я унаследовал базу данных, в которой одна из таблиц имеет первичный ключ, состоящий из закодированных значений (Часть 1 * 1000 + Часть 2) .
Я нормализовал этот столбец, но я не могу изменить старые значения.
Итак, теперь у меня есть
select ID from table order by ID
ID
100001
100002
101001
...
Я хочу найти «дырки» в таблице (точнее, первую «дырку» после 100000) для новых строк.
Я использую следующий выбор, но есть ли лучший способ сделать это?
select /* top 1 */ ID+1 as newID from table
where ID > 100000 and
ID + 1 not in (select ID from table)
order by ID
newID
100003
101029
...
База данных — Microsoft SQL Server 2000. Я нормально использую расширения SQL.
Перейти к ответу
Данный вопрос помечен как решенный
Ответы
10
SELECT (ID+1) FROM table AS t1
LEFT JOIN table as t2
ON t1.ID+1 = t2.ID
WHERE t2.ID IS NULL
select ID +1 From Table t1
where not exists (select * from Table t2 where t1.id +1 = t2.id);
Не уверен, будет ли эта версия быстрее, чем та, которую вы упомянули изначально.
Это решение должно дать вам первое и последнее значения идентификаторов «дыр», которые вы ищете. Я использую это в Firebird 1.5 для таблицы из 500 КБ записей, и хотя это занимает некоторое время, это дает мне то, что я хочу.
SELECT l.id + 1 start_id, MIN(fr.id) - 1 stop_id
FROM (table l
LEFT JOIN table r
ON l.id = r.id - 1)
LEFT JOIN table fr
ON l.id < fr.id
WHERE r.id IS NULL AND fr.id IS NOT NULL
GROUP BY l.id, r.id
Например, если ваши данные выглядят так:
ID
1001
1002
1005
1006
1007
1009
1011
Вы получите это:
start_id stop_id
1003 1004
1008 1008
1010 1010
Хотел бы я полностью отдать должное этому решению, но я нашел его на Xaprb.
Это решение не дает всех отверстий в таблице, только следующие свободные + первое доступное максимальное число в таблице — работает, если вы хотите заполнить пробелы в идентификаторах, + получить бесплатный номер идентификатора, если у вас нет пробела. .
Выберите numb + 1 из температуры
минус
выберите numb from temp;
От Как найти «пробел» в счетчике работы с SQL?
select
MIN(ID)
from (
select
100001 ID
union all
select
[YourIdColumn]+1
from
[YourTable]
where
--Filter the rest of your key--
) foo
left join
[YourTable]
on [YourIdColumn]=ID
and --Filter the rest of your key--
where
[YourIdColumn] is null
Лучший способ — создать временную таблицу со всеми идентификаторами
Затем сделайте левое соединение.
declare @maxId int
select @maxId = max(YOUR_COLUMN_ID) from YOUR_TABLE_HERE
declare @t table (id int)
declare @i int
set @i = 1
while @i <= @maxId
begin
insert into @t values (@i)
set @i = @i +1
end
select t.id
from @t t
left join YOUR_TABLE_HERE x on x.YOUR_COLUMN_ID = t.id
where x.YOUR_COLUMN_ID is null
Это даст вам полную картину, где ‘Низ’ означает начало разрыва, а ‘Верхний’ означает конец разрыва:
select *
from
(
(select <COL>+1 as id, 'Bottom' AS 'Pos' from <TABLENAME> /*where <CONDITION*/>
except
select <COL>, 'Bottom' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/)
union
(select <COL>-1 as id, 'Top' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/
except
select <COL>, 'Top' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/)
) t
order by t.id, t.Pos
Результаты Примечание: первая и Последний — это НЕПРАВИЛЬНЫЙ, и их не следует рассматривать, но их удаление значительно усложнит этот запрос, так что пока этого достаточно.
Недавно задумались над этим вопросом, и, похоже, это самый элегантный способ сделать это:
SELECT TOP(@MaxNumber) ROW_NUMBER() OVER (ORDER BY t1.number)
FROM master..spt_values t1 CROSS JOIN master..spt_values t2
EXCEPT
SELECT Id FROM <your_table>
Многие из предыдущих ответов вполне хороши. Однако все они не возвращают первое значение последовательности и / или не учитывают нижний предел 100000. Все они возвращают промежуточные дыры, но не самое первое (100001, если оно отсутствует).
Полное решение вопроса следующее:
select id + 1 as newid from
(select 100000 as id union select id from tbl) t
where (id + 1 not in (select id from tbl)) and
(id >= 100000)
order by id
limit 1;
Число 100000 должно использоваться, если первое число последовательности равно 100001 (как в исходном вопросе); в противном случае он должен быть изменен соответствующим образом
«limit 1» используется для того, чтобы иметь только первое доступное число вместо полной последовательности
Для людей, использующих Oracle, можно использовать следующее:
select a, b from (
select ID + 1 a, max(ID) over (order by ID rows between current row and 1 following) - 1 b from MY_TABLE
) where a <= b order by a desc;
Другие вопросы по теме
← →
Maacheba
(2009-02-12 19:05)
[0]
Есть таблица, назовем ее «MyTable», формат:
Number | FlagDeleting
Number — число, FlagDeleting — тоже число, если равно 1 — то запись считается уничтоженной в запросах (но физически из таблицы не удаляется).
Задача: найти первую свободную «дырку» в последовательности Number среди не помеченных на удаление записях.
Пример:
Number | FlagDeleting
================
1 | 0
6 | 0
4 | 0
2 | 0
Правильный ответ: 3
Еще пример:
Number | FlagDeleting
================
1 | 0
2 | 1
3 | 0
4 | 0
Правильный ответ: 2
Чтобы найти дырку — с успехом срабатывает такой код:
SELECT MyTable.Number + 1 from MyTable left join
MyTable m on (MyTable.Number + 1 = m.Number) where "
(m.Number is null) and (MyTable.Number+1 > X)
Где «X» — фактически задает тот лимит с которого искать дырку. Если X = 0, то дырка начинает искаться с числа 1, если задать X=5, то дырка начинает искаться 6 и т.д.
Вопрос в том, что нужно учесть столбец FlagDeleting, помеченые как удаленные записи просто не рассматривать. Если делать так:
SELECT MyTable.Number + 1 from MyTable left join
MyTable m on (MyTable.Number + 1 = m.Number) where "
(m.Number is null) and (MyTable.Number+1 > X) and (MyTable.FlagDeleting=0)
То такой запрос возвращает NULL.
Если условие MyTable.FlagDeleting=0
заменить на m.FlagDeleting=0
или их сочетание — тоже самое.
Не понимаю, почему так происходит и как это исправить?
P.S. База — SQLite
← →
Palladin ©
(2009-02-13 08:04)
[1]
Number надеюсь не используется как первичный ключ?
← →
Jack128_
(2009-02-13 08:35)
[2]
> m.FlagDeleting=0
это условие помести в
left join
MyTable m on (MyTable.Number + 1 = m.Number) and m.FlagDeleting<>0
← →
Jack128_
(2009-02-13 08:38)
[3]
> left join
> MyTable m on (MyTable.Number + 1 = m.Number) and m.FlagDeleting=0
Хотя навскидку моно и оставить в where, примерно в таком виде:
where (MyTable.Number+1 > X) and ((m.Number is null) or (MyTable.FlagDeleting=0))
← →
Jack128_
(2009-02-13 09:23)
[4]
Блин.
>
> where (MyTable.Number+1 > X) and ((m.Number is null) or
> (m.FlagDeleting=0))
вобщем сам разберешся, смысл, надеюсь понял..
← →
Johnmen ©
(2009-02-13 09:45)
[5]
> Maacheba (12.02.09 19:05)
Просто в условие соединения добавить and (m.FlagDeleting=0)
← →
Maacheba
(2009-02-13 11:57)
[6]
Никто не поможет?
← →
Maacheba
(2009-02-13 12:11)
[7]
Ух, почему-то при просмотре ветки она закешировалась, думал нет новых ответов…
Спасибо всем за помощь!
← →
Maacheba
(2009-02-13 12:12)
[8]
> Number надеюсь не используется как первичный ключ?
нет, конечно.
← →
MsGuns ©
(2009-02-13 12:14)
[9]
Такой запрос написать не проблема, но он будет выполняться медленно, однако механизм такого «резервирования» какой-то неуклюжий. Если Вы объясните великий смысл этого загадочного Number, нам будет много проще помочь
← →
MsGuns ©
(2009-02-13 12:15)
[10]
Пардон, не запрос, а хранимку или функцию (не знаком с лайтом)
← →
Кщд
(2009-02-13 12:29)
[11]
>Поиск «дырки» в записях
не ясно, какой смысл в этом поиске, если база данных — многопользовательская
← →
Виталий Панасенко
(2009-02-13 12:51)
[12]
> Кщд (13.02.09 12:29) [11]
лайт, кажись, как раз однопользовательский
← →
Кщд
(2009-02-13 13:02)
[13]
>Виталий Панасенко (13.02.09 12:51) [12]
как-будто многопользовательская…
http://www.sqlite.org/faq.html#q5
Multiple processes can have the same database open at the same time. Multiple processes can be doing a SELECT at the same time. But only one process can be making changes to the database at any moment in time, however.
← →
Johnmen ©
(2009-02-13 13:03)
[14]
Даже для однопользовательского проблема «дырок» — полная чушь…
← →
Maacheba
(2009-02-13 20:18)
[15]
Чего-то не получается
Давайте на реальной базе уж, чтобы мозги не пудрить.
NUM_GLOBAL — как раз та переменная, в которой надо найти дырку.
Activity — признак активности. Если 0 — то значит запись считается «удаленной», если больше нуля — значит не удалена.
Сам пример базы:
http://pic.ipicture.ru/uploads/090213/6tnSNRtsIy.gif
> > where (MyTable.Number+1 > X) and ((m.Number is null) or
>
> > (m.FlagDeleting=0))
>
> вобщем сам разберешся, смысл, надеюсь понял..
не разобрался
Сделал такой запрос:
SELECT Clients.NUM_GLOBAL + 1 from Clients left join Clients c on (Clients.NUM_GLOBAL + 1 = c.NUM_GLOBAL) where (Clients.NUM_GLOBAL+1 > 0) and ( (c.Activity=0) or (c.NUM_GLOBAL is null) )
Но он возвращает: 3 (вместо правильного ответа 1): http://pic.ipicture.ru/uploads/090213/X35ThyceyM.gif
> это условие помести в
>
> left join
сделал такой запрос:
SELECT Clients.NUM_GLOBAL + 1 from Clients left join Clients c on (Clients.NUM_GLOBAL + 1 = c.NUM_GLOBAL) and (c.Activity>0) where (Clients.NUM_GLOBAL+1 > 0) and (c.NUM_GLOBAL is null)
Но он тоже возвращает: 3 — http://pic.ipicture.ru/uploads/090213/S5jJqY2BsO.gif
НИ-ЧЕ-ГО не понимаю (
← →
Maacheba
(2009-02-14 12:40)
[16]
Может SQLite чего-то не так делает…
← →
sniknik ©
(2009-02-14 14:21)
[17]
> Может SQLite чего-то не так делает…
конечно не то… ведь он делает то, что ему говорят(/пишут), а не то что при этом думают…
хотя не знаю что там с SQLite, но и для access логика запросов неверная (не говоря уже об идее поиска ничего не значащих «дырок»)
вот так работает нормально (access!!!, но как видно логика изменена)SELECT TOP 1 t1.NUM_GLOBAL + 1 AS [Дырка] FROM
Clients t1 LEFT JOIN Clients t2 ON (t1.NUM_GLOBAL + 1) = t2.NUM_GLOBAL AND t2.Activity = 0
WHERE t2.NUM_GLOBAL IS NULL
← →
Maacheba
(2009-02-14 15:26)
[18]
sniknik © (14.02.09 14:21) [17]
это аналог выражения, которое я выше написал:
SELECT Clients.NUM_GLOBAL + 1 from Clients left join Clients c on (Clients.NUM_GLOBAL + 1 = c.NUM_GLOBAL) and (c.Activity>0) where (Clients.NUM_GLOBAL+1 > 0) and (c.NUM_GLOBAL is null)
только Activity>0 ты заменил на Activity = 0.
SQLite возвращает при этом запросе: 2
Хотя правильный ответ: 1
http://s52.radikal.ru/i137/0902/c9/ef9e9b991381.jpg
(зеркало): http://pic.ipicture.ru/uploads/090214/1x0B2LkXXj.gif
← →
sniknik ©
(2009-02-14 17:20)
[19]
> это аналог выражения, которое я выше написал:
ну пусть будет аналог.
> SQLite возвращает при этом запросе: 2
> Хотя правильный ответ: 1
а до того было, у «аналога»
> Но он тоже возвращает: 3 — http://pic.ipicture.ru/uploads/090213/S5jJqY2BsO.gif
на исходных данных
> Еще пример:
>
> Number | FlagDeleting
> ================
> 1 | 0
> 2 | 1
> 3 | 0
> 4 | 0
>
> Правильный ответ: 2
а теперь возвращает бывшее правильное 2… и опять не нравиться, теперь почему то правильным стала еденица. как понять тебя Саид?.
← →
sniknik ©
(2009-02-14 17:41)
[20]
и кстати, 1-у и не должно находить… она на первой записи и поэтому не может быть «дыркой», т.к. это начало отсчета. и с какой цифры бы оно не начиналось… в общем «дырки» это то что между, а начало с краю.
постаноу=вку задачи надо пересмотреть если тебе нужны не дырки а отсутствующие в каком то периоде/списке.
← →
Maacheba
(2009-02-14 19:05)
[21]
sniknik © (14.02.09 17:20) [19]
а до того было, у «аналога»
написано не просто «аналог», а «это аналог выражения… только Activity>0 ты заменил на Activity = 0»
sniknik © (14.02.09 17:20) [19]
а теперь возвращает бывшее правильное 2… и опять не нравиться
стоит заметить, что взяты разные примеры. В первом посте приведены данные от балды, чтобы показать СУТЬ задачи.
Само же тестирование делалось на реальной базе: http://pic.ipicture.ru/uploads/090213/6tnSNRtsIy.gif — и здесь правильный ответ: 1
sniknik © (14.02.09 17:41) [20]
постаноу=вку задачи надо пересмотреть если тебе нужны не дырки а отсутствующие в каком то периоде/списке
ну можно описать существующий смысл:
есть клиенты и у каждого клиента есть номер билета NUM_GLOBAL. Со временем клиенты могут удаляться физически (как запись из базы), а могут быть помечены как удаленные, при этом Activity выставляется в ноль. Для логики программы записи, где Activity стоит в 0 тоже самое, что этой записи вообще бы не было.
В таких условиях надо уметь искать НАИМЕНЬШИЙ доступный номер билета для выделения его новому клиенту. Нумерация билетов начинается с 1.
P.S. Задача такова, как я ее описал. Крики «ты лох» и «ты ничего не понимаешь», а также «тебе нужно не это, а другое» — просьба не озвучивать.
← →
sniknik ©
(2009-02-14 19:42)
[22]
> Само же тестирование делалось на реальной базе: http://pic.ipicture.ru/uploads/090213/6tnSNRtsIy.gif — и здесь правильный ответ: 1
вообще то, по описанию в [0], и здесь правильный ответ 2, или второй пример в [0] приводит неправильный ответ.
> P.S. Задача такова, как я ее описал.
да ну? а почему тогда при одинаковых исходных данных в разных постах у тебя верными считаются разные цифры?
и если вначале только СУТЬ, то почему из запроса не взята тоже только она и не подставлены сравнение на нужные значения? почему запрос взят as is?
> при этом Activity выставляется в ноль.
а в [0] во втором примере (на что я ориентировался) удаленной считается с FlagDeleting(Activity?) = 1
> В таких условиях надо уметь искать НАИМЕНЬШИЙ доступный номер билета для выделения его новому клиенту. Нумерация билетов начинается с 1.
ну так… введи точку отсчета — не стираемую запись со значением 0 и все, мой запрос будет работать… если ты конечно определишься наконец что у тебя считается удаленным а что нет, и поправишь под это, если конечно способен… а то ты видишь в выборке того что есть и присоединение к этому равнозначность выборке того что нет по одному способу игнорируя другой.
> Крики «ты лох» и «ты ничего не понимаешь», а также «тебе нужно не это, а другое» — просьба не озвучивать.
где реально кто то говорил, что «ты лох»? ну а то что «ты ничего не понимаешь» я думаю очевидно, иначе бы не спрашивал.
← →
Johnmen ©
(2009-02-14 19:53)
[23]
> Maacheba (14.02.09 19:05) [21]
Да-да, вместо того, чтобы возбухать, надо осознать, что ты ничего не понимаешь, и сделать попытку понять.
ЗЫ
Впрочем, если тебе завтра дадут задачу сделать велик с квадратными колесами, то ты можешь читать мантру «Задача такова, как я ее описал»
:))
← →
Maacheba
(2009-02-14 21:33)
[24]
> ну так… введи точку отсчета — не стираемую запись со значением
> 0 и все
без введения такой записи задачу средствами SQL решить невозможно?
> вообще то, по описанию в [0], и здесь правильный ответ 2,
> или
блин… Я прошу прощения, что запутал, но в первом посте колонка FlagDeleting, она имеет противоположное значение реальной колонки Activity из реальной базы.
Реально запись считается удаленной, если Activity в 0. Если не ноль — то запись актуальна.
Давайте рассуждать о реальной базе теперь. Если нужно — я переделаю примеры:
NUM_GLOBAL | Activity
================
1 | [не ноль]
6 | [не ноль]
4 | [не ноль]
2 | [не ноль]
Правильный ответ: 3
Еще пример:
NUM_GLOBAL | Activity
================
1 | [не ноль]
2 | 0
3 | [не ноль]
4 | [не ноль]
Правильный ответ: 2
← →
Сергей М. ©
(2009-02-14 23:21)
[25]
> Давайте рассуждать о реальной базе теперь
Ты ее
сам
лепил, базу эту ?
Или она досталась тебе в тяжелое наследство ?
Только честно уж, агрессивный ты наш) ..
← →
Германн ©
(2009-02-15 00:55)
[26]
> Только честно уж, агрессивный ты наш) ..
Против партизан почти нет приёмов. И это доказывают все исторические примеры, начинаю с середины прошлого века. А уж против агрессивных?
← →
Maacheba
(2009-02-15 13:17)
[27]
Народ, задача остается пока, решение не придумал. Кратко сформулирую задачу:
есть клиенты и у каждого клиента есть номер билета NUM_GLOBAL. Со временем клиенты могут удаляться физически (как запись из базы), а могут быть помечены как удаленные, при этом Activity выставляется в ноль. Для логики программы записи, где Activity стоит в 0 тоже самое, что этой записи вообще бы не было.
В таких условиях надо уметь искать НАИМЕНЬШИЙ доступный номер билета для выделения его новому клиенту. Нумерация билетов начинается с 1.
Примеры:
NUM_GLOBAL | Activity
================
1 | [не ноль]
6 | [не ноль]
4 | [не ноль]
2 | [не ноль]
Правильный ответ: 3 (потому что это наименьшее число, начиная с 1, для которого запись отсутствует или activity равно нулю).
Еще пример:
NUM_GLOBAL | Activity
================
1 | [не ноль]
2 | 0
3 | [не ноль]
4 | [не ноль]
Правильный ответ: 2 (потому что это наименьшее число, начиная с 1, для которого запись отсутствует или activity равно нулю).
← →
Maacheba
(2009-02-15 18:30)
[28]
Средствами SQL сделать это невозможно? ((
Время поджимает, поэтому сделаю так:
1) запрос на все данные и сортировка ORDER BY NUM_GLOBAL
2) вручную пробегаюсь от первой записи до последней, если следующая запись по NUM_GLOBAL отличается от предыдущей более, чем на единицу или если в следующей записи Activity=0, то значит нашел.
Правда, странно что это нельзя реализовать чисто в SQL, лишняя работа (
← →
Maacheba
(2009-02-15 18:32)
[29]
Удалено модератором
Примечание: Обсуждение модерирования
← →
sniknik ©
(2009-02-15 19:20)
[30]
> сходу решения никто не придумал.
да неужто прям бином Ньютона?… ;), чуток исправить то что я приводил (добавить поиск начала) и все будет под новые «правила»… пока ты их опять не поменял.
правда это сработает (с исправлениями конечно), могу исправить, для аксесс, mssql, vfp, даже под firebird который очень слабо знаю, и даже под нелюбимый оракл…. но вот для SQLite который в глаза не видел, и желания изучать нет… не обессудь.
> Сразу видно — вопрос для начинающих )
причем тут вопрос? ТЫ начинающий. т.к. ведешь себя соответственно.
Дырки в последовательности
- Главная
- Мамина школа
- Математика
- Ритм, чередование, орнамент
- Дырки в последовательности
Очередная игра на чередование и последовательности. Сегодня мы будем искать не продолжать последовательность, а вставлять нужные предметы, там где они пропущены
Подготовка к игре
Мы опять играли с орнаментом Зайцева. А вообще можно раскладывать любые предметы, главное чтобы их было по несколько штук.
Можно распечатать маленькие черно-белые картинки раскраски, раскрасить их и выкладывать последовательность из них: машина, трактор, самосвал, машин трактор, самосвал. Конечно, нужно не просто выкладывать, а играть с ними. Картинки самосвала, машины, трактора, можно скачать и распечатать. Для этого нажмите кнопку соц. сетей и подождите перезагрузки страницы.
[pwal id=»52495862″ description=»Нажми и скачай»]Скачать картинки для игры[/pwal]
Как играть
То есть у вас есть стоянка, где у каждого транспорта свое место. Вечером машины возвращаются на стоянку, и мы видим, что приехали машина, трактор, самосвал, машина, трактор, (пустое место), машина, трактор, самосвал и.т.д.
Предложите ребенку отгадать, кто еще не приехал с работы, какой транспорт?
Дети легко находят, что надо вставить в «дырку в последовательности», если четко проговаривать: машина, трактор, самосвал и.т.д.
Небольшое усложнение
Мы решили приплести еще одну игру.
Когда построили состав (у нас кусочки орнамента были вагончиками), и заполнили дырки в составе, то решили загрузить эти вагоны. Но загружать надо по правилам.
Я говорю: Во все НЕ зеленые вагоны надо загрузить НЕ треугольный груз; или так: во все НЕ овальные вагоны, НЕ розовый груз. Два отрицания в одном предложение, достаточно сложно для малышей. Если ребенок не справляется, оставьте только одно отрицание.
Всю игру легко адаптировать на интересы ребенка. Картинки можно подобрать любой тематики: зайчики, собачки, кошечки, птички.
У каждого ребенка есть свои любимые «темы для игр» — раскладывайте и играйте с ними. Ведь интерес ребенка превыше всего!
Оставить свой комментарий
#c# #linq #linq-to-sql
#c# #linq #linq-to-sql
Вопрос:
Я использую Linq to Sql для компактной базы данных SQL Server. Мне нужен быстрый способ найти первую дыру в столбце на основе целых чисел или, если их не существует, наибольшее число 1.
Если бы я делал это с помощью SQL, я бы сделал что-то вроде этого:
SELECT IdLegacy 1 FROM FLUID AS t1
LEFT JOIN FLUID as t2
ON t1.IdLegacy = t2.IdLegacy 1
WHERE t2.IdLegacy IS NULL
В принципе, мне нужно что-то похожее в Linq to Sql для достижения того же самого. Поскольку он будет вызываться при каждой вставке, мне нужно, чтобы он был быстрым и предпочтительно элегантным: -D.
Спасибо
Комментарии:
1. Но это решение уже не является быстрым — как linq может быть лучше?
2. Я не говорил, что linq должен обеспечить лучшее решение, просто я хотел похожее. Показанный SQL имеет приемлемую производительность, и любое предлагаемое решение должно работать как минимум так же хорошо.
Ответ №1:
Левое внешнее соединение выглядит так в LINQ to SQL
from t1 in fluid
join t2 in fluid on t1.LegacyId 1 equals t2.LegacyId into t3
from maybeGap in t3.DefaultIfEmpty()
where maybeGap == null
select new { t1 = t1 }
maybeGap
теперь отражает запись, которая является left outer join
из fluid. Возможно, поставщик LINQ для SQL Compact ограничен, поскольку SQL Compact очень ограничен, но это гайки и болты.
Вы можете протестировать это с помощью этого небольшого тестового примера:
var list = new List<int> { 1, 2, 3, 5 };
var q =
from x in list
join y in list on x 1 equals y into y
from z in y.DefaultIfEmpty()
where z == 0
select x 1
;
foreach (var item in q)
Console.WriteLine(item);
Выводит 4
и 6
, просто игнорируйте последнее, поскольку оно всегда будет там, и нет простого способа предотвратить это без использования оконных функций, которые не поддерживаются SQL Compact .
Ответ №2:
- Вы можете выполнять объединения в Linq
- Поскольку мне кажется, что вы пытаетесь решить проблему целостности базы данных низкого уровня, я бы вызвал вас.
Комментарии:
1. 2. Верно, клиент настаивает на сохранении старого столбца id как для старых, так и для новых записей. Триггеры невозможны в SQL CE.