合并两个没有公共字段的表

时间:2009-07-29 05:00:24

标签: sql-server union

我想学习如何组合两个没有共同字段的db表。我已经检查了UNION,但是MSDN说:

  

以下是使用UNION组合两个查询的结果集的基本规则:

     
      
  1. 所有查询中列的数量和顺序必须相同。
  2.   
  3. 数据类型必须兼容。
  4.   

但我根本没有共同的领域。我想要的只是将它们组合在一个表中,就像一个视图。

那我该怎么办?

提前致谢。

此致。

14 个答案:

答案 0 :(得分:108)

有很多方法可以执行此操作,具体取决于您 想要的内容。如果没有常用列,则需要确定是要引入公共列还是获取产品。

假设您有两个表:

parts:              custs:
+----+----------+   +-----+------+
| id | desc     |   |  id | name |
+----+----------+   +-----+------+
|  1 | Sprocket |   | 100 | Bob  |
|  2 | Flange   |   | 101 | Paul |
+----+----------+   +-----+------+

忘记实际列,因为在这种情况下,您很可能拥有客户/订单/部件关系;我刚刚使用这些列来说明了实现它的方法。

笛卡尔积将匹配第一个表中的每一行与第二个中的每一行:

> select * from parts, custs;
      id desc     id  name
      -- ----     --- ----
      1  Sprocket 101 Bob
      1  Sprocket 102 Paul
      2  Flange   101 Bob
      2  Flange   102 Paul

这可能不是您想要的,因为1000个零件和100个客户将产生100,000行,其中包含大量重复信息。

或者,您可以使用union来输出数据,但不能并排(您需要确保两种选择之间的列类型兼容,方法是使表列兼容或强制它们在选择中):

> select id as pid, desc, '' as cid, '' as name from parts
  union
  select '' as pid, '' as desc, id as cid, name from custs;
    pid desc     cid name
    --- ----     --- ----
                 101 Bob 
                 102 Paul
    1   Sprocket
    2   Flange

在某些数据库中,您可以使用rowid / rownum列或伪列来并排匹配记录,例如:

id desc     id  name
-- ----     --- ----
1  Sprocket 101 Bob
2  Flange   101 Bob

代码如下:

select a.id, a.desc, b.id, b.name
from parts a, custs b
where a.rownum = b.rownum;

它仍然喜欢笛卡尔积,但where子句限制行的组合方式以形成结果(所以根本不是笛卡尔积)。

我没有为此测试过SQL,因为它是我选择的DBMS的局限之一,这是正确的,我认为在经过适当考虑的架构中不需要它。由于SQL不保证其生成数据的顺序,因此除非您具有特定的关系或order by子句,否则每次执行查询时匹配都会更改。

我认为理想的做法是在两个表中添加一个列来指定关系。如果没有真正的关系,那么你可能没有尝试将它们与SQL并排放置。

如果您只是希望它们在报告或网页上并排显示(两个示例),那么正确的工具就是生成报告或网页的任何内容,再加上两个独立< / em> SQL查询以获取两个不相关的表。例如,BIRT(或Crystal或Jasper)中的两列网格,每个网格都有一个单独的数据表,或者一个HTML二列表(或CSS),每个都有一个单独的数据表。

答案 1 :(得分:22)

这是一个非常奇怪的请求,几乎可以肯定,在现实世界的应用程序中你永远不想做的事情,但从纯粹的学术角度来看,这是一个有趣的挑战。使用SQL Server 2005,您可以使用公用表表达式和row_number()函数并加入:

with OrderedFoos as (
    select row_number() over (order by FooName) RowNum, *
    from Foos (nolock)
),
OrderedBars as (
    select row_number() over (order by BarName) RowNum, *
    from Bars (nolock)
)
select * 
from OrderedFoos f
    full outer join OrderedBars u on u.RowNum = f.RowNum

这很有效,但它非常愚蠢,我只是作为一个“社区维基”答案,因为我真的不推荐它。

答案 2 :(得分:11)

SELECT *
FROM table1, table2

这会将table1中的每一行与table2(笛卡尔积)一起返回所有列。

答案 3 :(得分:3)

如果表没有公共字段,则无法在任何有意义的视图中组合数据。您最终可能会得到一个包含来自两个表的重复数据的视图。

答案 4 :(得分:2)

要获得两个表的有意义/有用的视图,通常需要确定每个表中的标识字段,然后可以在JOIN的ON子句中使用该标识字段。

在你看来:

SELECT T1.*, T2.* FROM T1 JOIN T2 ON T1.IDFIELD1 = T2.IDFIELD2

您提到没有字段是“常见的”,但是虽然标识字段可能不具有相同的名称,甚至可能是相同的数据类型,但您可以使用convert / cast函数以某种方式连接它们。

答案 5 :(得分:2)

为什么不使用简单的方法

    SELECT distinct *
    FROM 
    SUPPLIER full join 
    CUSTOMER on (
        CUSTOMER.OID = SUPPLIER.OID
    )

它为您提供了来自两个表的所有列,并返回来自客户和供应商的所有记录,如果客户有3条记录且供应商有2条,则供应商将在所有列中显示NULL

答案 6 :(得分:2)

Select 
DISTINCT  t1.col,t2col
From table1 t1, table2 t2

OR

Select 
DISTINCT  t1.col,t2col
From table1 t1 
cross JOIN  table2 t2

如果它的拥抱数据,它需要很长时间..

答案 7 :(得分:2)

尝试:

select * from table 1 left join table2 as t on 1 = 1;

这将带来两个表中的所有列。

答案 8 :(得分:1)

select 
    status_id, 
    status, 
    null as path, 
    null as Description 
from 
    zmw_t_status

union
select 
    null, 
    null, 
    path as cid, 
    Description from zmw_t_path;

答案 9 :(得分:1)

SELECT t1.col table1col, t2.col table2col
FROM table1 t1 
JOIN table2 t2 on t1.table1Id = x and t2.table2Id = y

答案 10 :(得分:0)

select * from this_table;

select distinct person from this_table

union select address as location from that_table 

drop wrong_table from this_database;

答案 11 :(得分:0)

在必须使用三个选择语句来完成此操作时非常困难

我尝试了所有建议的技术,但没有用

请参见以下脚本。请咨询您是否有替代解决方案

   select distinct x.best_Achiver_ever,y.Today_best_Achiver ,z.Most_Violator from 

    (SELECT  Top(4) ROW_NUMBER() over (order by tl.username)  AS conj, tl. 
     [username] + '-->' + str(count(*)) as best_Achiver_ever 
    FROM[TiketFollowup].[dbo].N_FCR_Tikect_Log_Archive tl
     group by tl.username
     order by count(*) desc) x
      left outer join 

(SELECT 
Top(4) ROW_NUMBER() over (order by tl.username)  as conj, tl.[username] + '-->' + str(count(*)) as Today_best_Achiver
FROM[TiketFollowup].[dbo].[N_FCR_Tikect_Log] tl
where convert(date, tl.stamp, 121) = convert(date,GETDATE(),121)
group by tl.username
order by count(*) desc) y 
on x.conj=y.conj

 left outer join 

(
select  ROW_NUMBER() over (order by count(*)) as conj,username+ '--> ' + str( count(dbo.IsViolated(stamp))) as Most_Violator from N_FCR_Ticket
where dbo.IsViolated(stamp) = 'violated' and  convert(date,stamp, 121) < convert(date,GETDATE(),121)
group by username
order by count(*) desc) z
on x.conj = z.conj

答案 12 :(得分:0)

联接无关表

enter image description here

演示SQL脚本

IF OBJECT_ID('Tempdb..#T1') IS NOT NULL  DROP TABLE #T1;

CREATE TABLE #T1 (T1_Name VARCHAR(75));

INSERT INTO #T1 (T1_Name) VALUES ('Animal'),('Bat'),('Cat'),('Duet');

SELECT * FROM #T1;

IF OBJECT_ID('Tempdb..#T2') IS NOT NULL  DROP TABLE #T2;

CREATE TABLE #T2 (T2_Class VARCHAR(10));

INSERT INTO #T2 (T2_Class) VALUES ('Z'),('T'),('H'); 

SELECT * FROM #T2;

要联接不相关的表,我们将引入一个序列号的通用联接列,如下所示。

SQL脚本

SELECT T1.T1_Name,ISNULL(T2.T2_Class,'') AS T2_Class FROM
( SELECT T1_Name,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS S_NO FROM #T1) T1
LEFT JOIN
( SELECT T2_Class,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS S_NO FROM #T2) T2
ON t1.S_NO=T2.S_NO;

答案 13 :(得分:-2)

请尝试此查询:

合并两个没有公共列的表:

SELECT * 
FROM table1 

UNION 

SELECT * 
FROM table2  
ORDER BY orderby ASC