Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2009.12.13;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.61 MB
Время: 0.008 c
15-1255811409
Юрий
2009-10-18 00:30
2009.12.13
С днем рождения ! 18 октября 2009 воскресенье


11-1209206318
zldo
2008-04-26 14:38
2009.12.13
ListView в DLL


1-1228486156
istok2
2008-12-05 17:09
2009.12.13
AV в обработчике сообщений...


2-1256126911
Nucer
2009-10-21 16:08
2009.12.13
Из WideChar в Char


4-1225119197
K1LLADR1LLA
2008-10-27 17:53
2009.12.13
Windows Script Host + COM + ThreadPool





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский