Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.12.13;
Скачать: CL | DM;

Вниз

SQL: Декартово произведение с произвольным множеством   Найти похожие ветки 

 
Kostafey ©   (2009-10-16 16:29) [0]

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

Итак, упрощаяю задачу до уровня сферического коня в вакууме.
Имеем Table1. В ней единственное поле Field1 с некоторыми данными.

выполняем:
select Table1.Field1 from Table1

получаем:

Field1
------
Мама
мыла
раму


Необходимо сформулировать запрос, чтобы получить декартово прооизведение
с произволным множеством, например 1,2,3, т.е.

Field1  arbitrarySet
------  ------------
Мама      1
Мама      2
Мама      3
мыла      1
мыла      2
мыла      3
раму      1
раму      2
раму      3


Подскажите, пожалуйста, как написать такой запрос.


 
Kostafey ©   (2009-10-16 16:33) [1]

СУБД: MS SQL Server 2005, если это имеет значение.


 
Рамиль ©   (2009-10-16 16:38) [2]

А почему нельзя множество загнать в табличку?


 
Kostafey ©   (2009-10-16 16:43) [3]

> [2] Рамиль ©   (16.10.09 16:38)
> А почему нельзя множество загнать в табличку?

Можно и загнать. Просто создавать табличку ради нескольких цифр как-то...
Есть другие варианты?


 
картман ©   (2009-10-16 16:45) [4]

creaTE table #t(st VARCHAR(10))
insert into #t (st)
values ("1")

insert into #t (st)
values ("2")

insert into #t (st)
values ("3")

select a.*
 from #t a, #t b

drop table #t


 
Kostafey ©   (2009-10-16 16:47) [5]

> [4] картман ©   (16.10.09 16:45)

Эх. Ладно. Спасибо. Будем делать так.


 
картман ©   (2009-10-16 16:50) [6]


> Kostafey ©   (16.10.09 16:47) [5]

почему эх?


 
картман ©   (2009-10-16 16:53) [7]

Или надо было посчитать повторы?

create table #t(st VARCHAR(10))

insert into #t (st)
values ("a")

insert into #t (st)
values ("b")

insert into #t (st)
values ("c")

select a.* Field1, row_number() over (partition by a.st order by a.st) arbitrarySet
 from #t a, #t b

drop table #t


 
Kostafey ©   (2009-10-16 17:06) [8]

> [6] картман ©   (16.10.09 16:50)
> почему эх?

Думал можно без временной таблицы.
Раз нет - вы мне сэкономили кучу времени.
Спасибо.


 
картман ©   (2009-10-16 17:30) [9]


> Kostafey ©   (16.10.09 17:06) [8]

да временная таблица просто так - напиши любую свою


 
картман ©   (2009-10-16 17:31) [10]

select t1.field1
from table1 t1, table1 t2


 
b z   (2009-10-16 17:37) [11]


> Думал можно без временной таблицы.
CTE возможно тут поможет.


 
Медвежонок Пятачок ©   (2009-10-16 18:27) [12]

declare @x xml;
set @x = "<item/><item/><item/><item/>";
select t.fieldname
from tablename t, @x.nodes("/item") as A(B)


 
Медвежонок Пятачок ©   (2009-10-16 18:39) [13]

причем тело xml не обязательно формировать динамически.
можно один раз создать в бд xml схему или просто таблицу c одним полем.
засунуть туда документ типа
<item count="1"/>
<item count="2"/>
<item count="2"/>
<item count="3"/>
<item count="3"/>
<item count="3"/>
...
<item count="n"/>
.....
<item count="n"/>

и для .nodes указывать "/item[@count=n]"


 
Медвежонок Пятачок ©   (2009-10-16 19:21) [14]

либо вообще вот так

declare @x xml;
set @x = replicate("<item/>",3);
select t.fieldname
from tablename t, @x.nodes("/item") as A(B)


 
Григорьев Антон ©   (2009-10-16 19:43) [15]

Не уверен, что это пройдёт в именно в MS SQL, но что-то типа такого

SELECT Table1.Field1
LEFT JOIN (SELECT 1 FROM Table1 UNION SELECT 2 FROM Table1 UNION SELECT 3 FROM Table1) ON 1=1


 
sniknik ©   (2009-10-16 21:18) [16]

> Не уверен, что это пройдёт в именно в MS SQL
вообще, для mssql подзапросы это "родное", как и временные таблицы, хотя с самим синтаксисом не уверен, указание таблиц в подзапросе лишнее, а алиасов нет (главным образом для подзапроса), без алиасов оно не будет знать что с чем вязать, нужны обязательно.
должно сработать такое

select t.Field1, s.arbitrarySet
from Table1 AS t, (SELECT 1 AS arbitrarySet UNION SELECT 2 UNION SELECT 3) AS s


 
Kostafey ©   (2009-10-16 22:27) [17]

> [15] Григорьев Антон ©   (16.10.09 19:43)
> [16] sniknik ©   (16.10.09 21:18)
> select t.Field1, s.arbitrarySet
> from Table1 AS t, (SELECT 1 AS arbitrarySet UNION SELECT
> 2 UNION SELECT 3) AS s

Вай класс! Спасибо! То что нужно.
Только я не понял зачем нужен алиас "основной" таблицы?
Так прекрасно работает:

select Table1.Field1, s.arbitrarySet
from Table1, (SELECT 1 AS arbitrarySet UNION SELECT 2 UNION SELECT 3) AS s


 
sniknik ©   (2009-10-16 22:32) [18]

> нужен алиас "основной" таблицы?
для однообразия, + запись короче, вот будет вместо одного поля нужда указать двадцать поймешь, а попользуешься привыкнешь. (что советую сделать побыстрее, т.к. сам видишь есть варианты когда это не просто удобство, но и синтаксис)


 
sniknik ©   (2009-10-16 22:35) [19]

кстати AS можно не писать, короткая форма указания алиаса без него.


 
Kostafey ©   (2009-10-16 22:38) [20]

> [18] sniknik ©   (16.10.09 22:32)
> для однообразия, + запись короче, вот будет вместо одного
> поля нужда указать двадцать поймешь

Я не пытаюсь спорить, но без дополнительных алиасов мне
как-то читать проще. Меньше искусственных элементов.
Впредь буду учитывать вашу точку зрения.

Кстати, так тоже работает:

select t.Field1, s.arbitrarySet
from Table1 as t
left join (SELECT 1 AS arbitrarySet UNION SELECT 2 UNION SELECT 3) s on 1=1


 
Игорь Шевченко ©   (2009-10-16 22:44) [21]

Завидуйте:

WITH foo AS (SELECT /*+ materialize */ level FROM dual CONNECT BY level <= 100000)
SELECT rownum id FROM foo foo1, foo foo2 WHERE rownum < 2000000000


Два миллиарда записей без всяких объектов в схеме :)


 
Медвежонок Пятачок ©   (2009-10-16 22:44) [22]

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


 
sniknik ©   (2009-10-16 22:44) [23]

> Кстати, так тоже работает:
а чего бы ему так не работать? это просто другая форма записи того же, но вот ты алиас убери...

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


 
sniknik ©   (2009-10-16 22:47) [24]

> Завидуйте:
хм. в 2005м тоже ввели порядковый номер... надо попробовать.


 
Kostafey ©   (2009-10-16 22:51) [25]

> WITH foo AS (SELECT /*+ materialize */ level FROM dual CONNECT
> BY level <= 100000)
> SELECT rownum id FROM foo foo1, foo foo2 WHERE rownum <
> 2000000000

А прокомментировать как это работает можно?

> [23] sniknik ©   (16.10.09 22:44)
> но вот ты алиас убери...

То поставь, то убери.
Ничего не понимаю! (с)

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

Я честно пытался понять смысл фразы, но не смог.
Можно это как-то попроще сказать? :)


 
Медвежонок Пятачок ©   (2009-10-16 22:55) [26]

А прокомментировать как это работает можно?

Орокол.


 
sniknik ©   (2009-10-16 23:00) [27]

> Можно это как-то попроще сказать? :)
выборка из таблицы повторит значение по количеству строк, а union после уберет повторяющиеся, т.е. в итоге получишь тоже самое но после выполнения ненужных операций.


 
Медвежонок Пятачок ©   (2009-10-16 23:07) [28]

[14] все равно круче всех и главное лаконичнее
:)


 
Игорь Шевченко ©   (2009-10-16 23:23) [29]


> А прокомментировать как это работает можно?


можно.
оператор CONNECT BY LEVEL увеличивает LEVEL на единицу (начиная с 1) и помещает новый результат в результирующий набор данных, пока будет истинно условие (в данном случае, пока LEVEL <= 100000), в итоге, получаем запрос, генерирующий 100000 записей. WITH ... AS (SELECT ... ) - это присвоение алиаса результату запроса, для того, чтобы результирующий набор данных мог участвовать во внешних запросах по этому алиасу (разумеется, можно SELECT для этого алиаса написать два раза в явном виде, но громоздко).

Во внешнем запросе обычное декартово произведение "двух таблиц". rownum - псевдостолбец, присваиваемый каждой записи результирующего набора (до выполнения сортировки), его можно использовать в условиях, учитывая, что начинает он присваиваться с 1 и для того, чтобы он увеличивался, необходимо, чтобы все условия запроса были истинными (то есть, rownum > 10 не сработает никогда)

Как смог :)


 
Медвежонок Пятачок ©   (2009-10-16 23:26) [30]

Кстати, хотел спросить....
Если уж вы извращаетесь с юнионами, то не проще ли извращаться по простому?

select * from table
union all
select * from table
union all
select * from table
union all
select * from table
union all
select * from table


 
Игорь Шевченко ©   (2009-10-16 23:31) [31]

И еще:

Подсказка /*+ materialize */ предлагает сформировать набор из 100000 записей один раз, а не высчитывать два раза (по количеству наборов в декартовом произведении)


 
Kostafey ©   (2009-10-16 23:37) [32]

> [29] Игорь Шевченко ©   (16.10.09 23:23)

Спасибо, но до оракла мы пока не доросли-сс. :)


> [27] sniknik ©   (16.10.09 23:00)
> выборка из таблицы повторит значение по количеству строк,
> а union после уберет повторяющиеся, т.е. в итоге получишь
> тоже самое но после выполнения ненужных операций.

Да что ж я такой тупой-то!?
Т.е. это относится к обсуждению различий между

select Table1.Field1, s.arbitrarySet
from Table1
left join (SELECT 1 AS arbitrarySet UNION SELECT 2 UNION SELECT 3) s on 1=1

и
select Table1.Field1, s.arbitrarySet
from Table1, (SELECT 1 AS arbitrarySet UNION SELECT 2 UNION SELECT 3) AS s

?


 
SELECT ©   (2009-10-16 23:43) [33]

вообще есть предположение, что ты уже предлагаешь (отвратительное) решение задачи, которую не озвучил.
почему ты думаешь, что твоё вИденье решения достойно хоть какого-то обсуждения?
и м.б. всё же сформулировать её, задачу?


 
Kostafey ©   (2009-10-16 23:48) [34]

> [33] SELECT ©   (16.10.09 23:43)

Я не против такой точки зрения, но стиль ее изложения
попахивает троллизмом.
Да, я, конечно, думал о том, чтобы изложить задачу.
Вопрос в том до какого уровня абстракции?
До уровня реальных таблиц и запросов?
Обсуждаение потеряет наглядность.
В упрощенном виде?


 
SELECT ©   (2009-10-16 23:54) [35]


> Kostafey ©   (16.10.09 23:48) [34]

изложи как есть, без формализации, простым обывательским языком )


 
Kostafey ©   (2009-10-16 23:55) [36]

Есть еще кто-то, кто бы придерживался того же мнения,
что необходимо сформулировать задачу ПОЛНОСТЬЮ?


 
Kostafey ©   (2009-10-16 23:56) [37]

> [35] SELECT ©   (16.10.09 23:54)

Хорошо, извольте... несколько минут...


 
SELECT ©   (2009-10-16 23:58) [38]


> Kostafey ©   (16.10.09 23:56) [37]

не ну ты будь готов к потоку уточняющих вопросов )


 
Kostafey ©   (2009-10-17 00:08) [39]

Необходимо периодически отсылать накапливаемые сведения.
Формат пересылки ужасен до безобразия, но
"Делай, что сказал Купец, вот и будешь молодец!
А поссоришься с купцом и окажешься глупцом."

Каждая запись представляет из себя:
-дата
-номер подразделения
-номер показателя (их 6, вот их я и обозвал произвольным множеством)
-значение показателя для 1-го типа
...
-значение показателя для 8-го типа

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

Например, если количество подразделений x, а номеров показателей y,
то в результирующем наборе данных за сутки должно быть x*y записей
- хоть тресни.
Событий, формирующих значение показателя для i-го типа за эти сутки
может и не произойти. Будет просто null, но номера показателей должны
присутствовать все.

Моя стратегия:
Высчитывать значение показателя для i-го типа в подзапросе в зависимости
от текущего номера показателя.

Кто-нибудь что-нибудь понял? :)


 
Kostafey ©   (2009-10-17 00:11) [40]

> [38] SELECT ©   (16.10.09 23:58)
> не ну ты будь готов к потоку уточняющих вопросов )

Это всегда пожалуйста, конечно. :)


 
SELECT ©   (2009-10-17 00:12) [41]

всё просто:
строишь декартово произведение всех показателей и подразделений (надеюсь, что они в справочниках),
потом это джойнишь слева собственно таблицей, где "Каждая запись представляет из себя:"


 
Kostafey ©   (2009-10-17 00:22) [42]

> строишь декартово произведение всех показателей и подразделений
> (надеюсь, что они в справочниках),

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

Список подразделений - да справочник.
Справочиника показателей не существует.
Более того, сама суть этих признаков, на
основе которых формируются показатели
зашиты в разные поля разных типов той же
самой таблицы из которой вычленяется
значение показателя для i-го типа.

Да, верно, БД даже не в 1-й нормальной форме.
Струкура БД снизошла на грешную землю с
Небес, там десятки тысяч записей и менять
ее никто не собирается.


 
SELECT ©   (2009-10-17 00:26) [43]


> Kostafey ©   (17.10.09 00:22) [42]

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

ЗЫ

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


это называется абзац. т.е. приплыли )))


 
SELECT ©   (2009-10-17 00:29) [44]

"бардак систематизации не поддается" (с)


 
Kostafey ©   (2009-10-17 00:30) [45]

> тогда попробуй вычленить запросом показатели - это и будет
> виртуальный справочник.

А смысл? Его все равно нужно будет делать
left join, при том что для каждой записи
подразделения должно быть декартово произведение
с множеством показателей.
Можно с таким же успехом просто перечислить
их 1,2,3... как и было сделано выше.


 
Kostafey ©   (2009-10-17 00:31) [46]

> "бардак систематизации не поддается" (с)

Мне уже не первый раз приходится это читать
на дельфимастере в здрес тех задач, с которыми
приходится иметь дело. :))


 
SELECT ©   (2009-10-17 00:40) [47]


> Kostafey ©   (17.10.09 00:30) [45]
> А смысл? Его все равно нужно будет
> делать left join, при том что для каждой записи подразделения
> должно быть декартово произведение с множеством показателей.

не left, а декартово.
а вообще я что-то перестал понимать - то надо, то не надо...
вот же схема:
SELECT * FROM <подразделения>, <показатели>
LEFT JOIN <таблица, где "Каждая запись представляет из себя:">

непонятно, в чем успех "просто перечислить"? кого перечислить? откуда узнали, сколько перечислить?


 
Kostafey ©   (2009-10-17 00:53) [48]

> не left, а декартово.
> а вообще я что-то перестал понимать - то надо, то не надо...
> вот же схема:
> SELECT * FROM <подразделения>, <показатели>
> LEFT JOIN <таблица, где "Каждая запись представляет из себя:">

Надо, всегда надо :) Я просто то же самое в другом виде написал:

SELECT * FROM <подразделения>
LEFT JOIN <показатели>
LEFT JOIN <таблица>, где "Каждая запись представляет из себя:


где LEFT JOIN <показатели>:
left join (SELECT 1 AS ID_TYPE_INDEX UNION SELECT 2 UNION SELECT 3
          UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) typeIndex on 1=1



> непонятно, в чем успех "просто перечислить"?

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

> кого перечислить?

Все показатели.

> откуда узнали, сколько перечислить?

Их перечень задан.


 
SELECT ©   (2009-10-17 01:00) [49]

последние вопросы - зачем LEFT JOIN <показатели>?
и кем, когда и в какой форме "Их перечень задан"?


 
Kostafey ©   (2009-10-17 01:02) [50]

> и кем, когда и в какой форме "Их перечень задан"?

ТЗ, вестимо ;)
Я уже писал:
> -номер показателя (их 6, вот их


 
sniknik ©   (2009-10-17 12:42) [51]

> Т.е. это относится к обсуждению различий между
нет, это относится к лишним таблицам в оригинальном запросе, с чего началось, читай сначала, и повнимательнее.


 
Kostafey ©   (2009-10-17 14:16) [52]

> [51] sniknik ©   (17.10.09 12:42)

В смысле использования временных таблиц?


 
sniknik ©   (2009-10-17 14:52) [53]

в смысле запроса который я исправил, и объяснил почему...
Григорьев Антон ©   (16.10.09 19:43) [15]
а вот почему ты это объяснение пытаешься применить к чему угодно но только не этому, загадка...


 
Kostafey ©   (2009-10-17 15:12) [54]

> [53] sniknik ©   (17.10.09 14:52)

Уф, ура, наконец-то понял. А то уж боялся так и останусь неучем :))
Спасибо!

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

Схематично:
select
 t.Field1,
 s.arbitrarySet,
 q.value
from Table1 AS t, (SELECT 1 AS arbitrarySet UNION SELECT 2 UNION SELECT 3) AS s
left join (
   select
       CASE someVariable
           WHEN 1 THEN "a"
           WHEN 2 THEN "b"
           WHEN 3 THEN "c"
           ELSE "d"
       END as value
) q on q.someVariable = s.arbitrarySet


Это, конечно не работает...
Конечно, на месте "a", "b", "c" будут свои запросы.


 
Kostafey ©   (2009-10-17 16:25) [55]

> [54] Kostafey ©   (17.10.09 15:12)

Сам про себя: а нафига я тут вообще left join приплел? :)


 
SP   (2009-10-17 16:35) [56]


> Необходимо сформулировать запрос, чтобы получить декартово
> прооизведение
> с произволным множеством, например 1,2,3, т.е.


Создай таблицу с этим самым произвольным множеством.
А потом
select Table1.Field1, Table2. from Table1.arbitrarySet from Table1,Table2

Тем более что это самое "Произвольное" множество - как я понимаю не совсем произвольное и чем-то должно определяться... Вот и в данном случае будет определяться содержимым Table2
Да и не мешало бы знать цели такой задачи, тогда возможно бы и другое более подходящее решение нашлось бы...


 
Kostafey ©   (2009-10-17 17:05) [57]

> from Table1.arbitrarySet from Table1,Table2

Это что значит?


> Да и не мешало бы знать цели такой задачи, тогда возможно
> бы и другое более подходящее решение нашлось бы...

см. > [39] Kostafey ©   (17.10.09 00:08)


 
SP   (2009-10-17 17:19) [58]

Ой, блин... Это издержки копипаста...
Имелось ввиду:

select Table1.Field1, Table2.arbitrarySet from Table1,Table2



Страницы: 1 2 вся ветка

Текущий архив: 2009.12.13;
Скачать: CL | DM;

Наверх




Память: 0.63 MB
Время: 0.015 c
2-1256653014
wq
2009-10-27 17:16
2009.12.13
record или packed record


2-1256109863
RWolf
2009-10-21 11:24
2009.12.13
AnsiExtractQuotedStr(PChar(str), ...)


15-1255552208
Юрий
2009-10-15 00:30
2009.12.13
С днем рождения ! 15 октября 2009 четверг


15-1255282877
fics)
2009-10-11 21:41
2009.12.13
asm


15-1255863244
POOP
2009-10-18 14:54
2009.12.13
Если в bat файле