Объединение таблиц (без предложения) - PullRequest
0 голосов
/ 01 октября 2009

Я хочу присоединиться к таблицам и получить следующий вывод

Table1

TestId1
----------
one
two
three
four
five
six
seven
eight

Table2

TestId2
----------
fiftythree
fiftyfour
fiftytwo
fiftyfive
fiftyone

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

Как альтернативный ответ, они также могут быть назначены случайным образом.

TestId1        TestId2   
----------     ----------
one           fiftythree
two           fiftyfour 
three         fiftytwo  
four          fiftyfive 
five          fiftyone  
six           fiftythree
seven         fiftyfour 
eight         fiftytwo  

Ответы [ 6 ]

5 голосов
/ 01 октября 2009

Попробуйте это:

SELECT t1.name, t2.name FROM
(
    SELECT (ROW_NUMBER() OVER(ORDER BY name)-1)%(SELECT COUNT(*) FROM test2) AS j,* 
    FROM test1
) t1
INNER JOIN 
(
    SELECT ROW_NUMBER() OVER(ORDER BY name)-1 AS j,* 
    FROM test2
) t2 ON t1.j = t2.j
ORDER BY t1.name

В деталях:

SELECT (ROW_NUMBER() OVER(ORDER BY name)-1) AS j,* 
FROM test1

Возвращает:

0 | one
1 | two
2 | three
3 | four
4 | five
5 | six
6 | seven
7 | eight

Это:

SELECT ROW_NUMBER() OVER(ORDER BY name)-1 AS j,* 
FROM test2

Возвращает:

0 | fiftythree
1 | fiftyfour
2 | fiftytwo
3 | fiftyfive
4 | fiftyone

Все, что вам нужно сделать, это разделить (% - я не знаю английского названия этого) первый столбец самой длинной таблицы на количество элементов в более коротком:

SELECT (ROW_NUMBER() OVER(ORDER BY name)-1)%(SELECT COUNT(*) FROM test2) AS j,* 
FROM test1

Возвращает:

0 | one
1 | two
2 | three
3 | four
4 | five
0 | six
1 | seven
2 | eight

Все, что вам нужно сделать сейчас, это объединить обе таблицы в первом столбце.

Это решение сделано с использованием только одного запроса, но предполагается, что в таблице1 больше элементов, чем в таблице2. Если вам не нравится это решение, я просто дал вам хорошую основу для написания процедуры хранения.

1 голос
/ 01 октября 2009

Я предпочитаю случайные процессы, поэтому выбрал [псевдо-] случайное решение ;-)

Это также требует "индуцирования" номера строки в таблице 2, но соединение с таблицей 1 управляется некоторым хешем [по модулю числа строк таблицы 2] в некоторых столбцах таблицы 1 (необязательно должен быть TestId1 ).

SELECT T1.TestId1, T2.TestId2 
FROM Table1 T1
JOIN (
  SELECT (ROW_NUMBER() OVER(ORDER BY TestId2) - 1) AS RowNum, TestId2 
  FROM Table2
) T2 ON ABS(HashBytes ('MD5', T1.TestId1) % (SELECT COUNT(*) FROM Table2))
        = T2.RowNum
ORDER BY t1.TestId1
1 голос
/ 01 октября 2009

Это работает и имеет только один курсор:

if exists(select object_id('tempdb..#TestId1'))
drop table #TestId1

if exists(select object_id('tempdb..#TestId2'))
drop table #TestId2

if exists(select object_id('tempdb..#result'))
drop table #result

create table #TestId1(col_1 varchar(100))

create table #TestId2(col_2 varchar(100))

create table #result (col_1 varchar(100), col_2 varchar(100))

set rowcount 0

insert into #TestId1(col_1 )
select col='one'
union all select col='two'
union all select col='three'
union all select col='four'
union all select col='five'
union all select col='six'
union all select col='seven'
union all select col='eigh'

insert into #TestId2(col_2 )
select col='fiftythree'
union all select col='fiftyfour'
union all select col='fiftytwo'
union all select col='fiftyfive'
union all select col='fiftyone'

DECLARE @sectblcnt int
select @sectblcnt=count(*) from #TestId2

DECLARE @sectableNo int

DECLARE @rowno int

declare @col_1 varchar(100), @col_2 varchar(100)

set @rowno=0

DECLARE curs CURSOR FOR SELECT col_1 FROM #TestId1

OPEN curs

FETCH NEXT FROM curs INTO @col_1

WHILE @@FETCH_STATUS = 0
BEGIN
set @rowno=@rowno+1;

set @sectableNo = @rowno % @sectblcnt
set rowcount @sectableNo

select @col_2=col_2 from #TestId2

insert into #result(col_1, col_2)
    values(@col_1, @col_2)

FETCH NEXT FROM curs 
INTO @col_1
END 

CLOSE curs

DEALLOCATE curs

set rowcount 0

select * from #result
1 голос
/ 01 октября 2009

Ваше альтернативное решение является единственным

SELECT
    TestID1,
    TestID2
FROM
    (SELECT COUNT(*) AS Count1 FROM Table1) C1 --one row
    CROSS JOIN
    (SELECT COUNT(*) AS Count2 FROM Table2) C2 --one row
    CROSS JOIN
    (
    SELECT
        ROW_NUMBER() OVER (ORDER BY TestID1) AS Rank1,
        TestID1,
    FROM
        Table1
    ) t1
    JOIN
    (
    SELECT
        ROW_NUMBER() OVER (ORDER BY TestID1) AS Rank2,
        TestID2,
    FROM
        Table2
    ) t2 ON
         t1.Rank1 % CASE WHEN C1.Count1 > C2.Count2 THEN C2.Count2 ELSE 2000000000 END
         =
         t2.Rank2 % CASE WHEN C2.Count2 > C1.Count1 THEN C1.Count1 ELSE 2000000000 END
ORDER BY
    t1.Rank1, t2.Rank2
0 голосов
/ 01 октября 2009

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

0 голосов
/ 01 октября 2009

Возможно, вы захотите попробовать присоединиться к ROWNUM.

http://www.adp -gmbh.ch / ора / SQL / rownum.html

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