合并两个没有公共字段的表
Posted
技术标签:
【中文标题】合并两个没有公共字段的表【英文标题】:Combine two tables that have no common fields 【发布时间】:2010-11-14 22:47:20 【问题描述】:我想学习如何组合两个没有共同字段的数据库表。我检查过 UNION 但 MSDN 说:
以下是使用 UNION 组合两个查询的结果集的基本规则:
所有查询中列的数量和顺序必须相同。 数据类型必须兼容。
但我根本没有共同的领域。我只想像视图一样将它们组合在一个表中。
那我该怎么办?
【问题讨论】:
对于那些想不出一个合乎逻辑的现实世界用法的人,想象一下:你有一张礼品券表。您正在对数据库进行一些手动更正,并且您希望为查询结果中的 N 人保留(设置会员 ID)N 的优惠券。您可以使用游标,或用另一种语言编写的应用程序,但带有 CTE 的干净 sql 正好符合要求,而无需离开 SQL 会话。 - 行号是要走的路 这个问题不清楚。 “结合”没有任何意义。 minimal reproducible example 【参考方案1】:有很多方法可以做到这一点,具体取决于您真正想要什么。没有通用栏目,你需要决定是要引入通用栏目还是要产品。
假设你有两张桌子:
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 行包含大量重复信息。
或者,您可以使用联合来仅输出数据,但不能并排(您需要通过使表列兼容或强制它们来确保两个选择之间的列类型兼容在选择中):
> select id as pid, desc, null as cid, null as name from parts
union
select null as pid, null 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 并排放置。
如果您只是希望它们在报告或网页上并排显示(两个示例),那么执行此操作的正确工具就是生成您的报告或网页,再加上两个独立 获取两个不相关的表的 SQL 查询。例如,BIRT(或 Crystal 或 Jasper)中的两列网格每个都有一个单独的数据表,或者一个 html 两列表(或 CSS)每个都有一个单独的数据表。
【讨论】:
谢谢,这是非常好的答案,并向我展示了实现解决方案的更好方法。 mysql中是否有rownum或rowid? 这是我最喜欢的 mysql 答案! “这可能不是你想要的”——但它是……你是如何做到这一点的? @pstanton,您如何在该段之前的代码块中实现这一点,select * from parts, custs
。【参考方案2】:
这是一个非常奇怪的请求,几乎可以肯定,这是您在实际应用程序中永远不想做的事情,但从纯粹的学术角度来看,这是一个有趣的挑战。使用 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
这可行,但它非常愚蠢,我仅将其作为“社区 wiki”答案提供,因为我真的不推荐它。
【讨论】:
+1 是的,行号是可行的方法,但我会使用内部连接。对于现实世界的用法,请参阅我对问题的评论 -) 这就是我需要的!我的任务是在两个表之间实现 FK 约束,这两个表的唯一公共字段是一对多关系上的 id,例如。 TblA 有 5 个 TblB 和 5 个 TblC,但业务逻辑更改意味着每个 TblC 现在都需要与 TblB 建立 1-1 关系。我必须追溯填充此关系,以便该字段可以变得独特且不可为空。这为我提供了一种方法来填充系统中已有的历史数据 有是一种用法,用于您想要比较两个表的场景,其中包含旧数据和新数据,[您的应用程序数据库依赖于其他一些公司数据库]其中一些 主脑 人came
,并更改了主数据! -- 当你想see
差异 而不是使用not in
和except
的东西时 -- 不过对我来说是不错的选择:)【参考方案3】:
SELECT *
FROM table1, table2
这会将 table1 中的每一行与返回所有列的 table2(笛卡尔积)连接起来。
【讨论】:
如果它们是不同的数据库表怎么办?谢谢。 这会导致交叉连接,这似乎不是他想要的。 这在特定情况下很有用。如果我必须对数据库进行三次访问,其中每个查询将返回一行并且每个查询都会产生网络延迟时间,那么我可以将三个查询组合成一个查询,例如 select * from (select x from tab1 where condition1), select y from tab2 where condition2), (select z from tab3 where condition3);【参考方案4】: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;
【讨论】:
它将忽略其中一个字段名称,我认为您只需将字段名称别名放在最后一个联合上 这个派上用场了——效率很高【参考方案5】:尝试:
select * from table 1 left join table2 as t on 1 = 1;
这将带来两个表中的所有列。
【讨论】:
感谢您提供此代码 sn-p,它可能会提供一些即时帮助。一个正确的解释would greatly improve 其教育价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有类似但不相同的问题的读者更有用。请edit您的答案添加解释,并说明适用的限制和假设。 你能解释一下这与不使用交叉连接有什么不同吗?【参考方案6】:如果表格没有公共字段,则无法在任何有意义的视图中组合数据。您更有可能最终得到一个包含两个表中重复数据的视图。
【讨论】:
【参考方案7】:要获得两个表的有意义/有用的视图,您通常需要从每个表中确定一个标识字段,然后可以在 JOIN 的 ON 子句中使用该字段。
那么在你看来:
SELECT T1.*, T2.* FROM T1 JOIN T2 ON T1.IDFIELD1 = T2.IDFIELD2
您提到没有字段是“通用的”,但虽然标识字段可能没有相同的名称甚至是相同的数据类型,但您可以使用 convert / cast 函数以某种方式加入它们。
【讨论】:
即使没有任何直接共享的字段,表之间也必须存在某种关系才能使视图有意义。需要在 ON 子句中捕获这种关系。【参考方案8】:你为什么不使用简单的方法
SELECT distinct *
FROM
SUPPLIER full join
CUSTOMER on (
CUSTOMER.OID = SUPPLIER.OID
)
它为您提供两个表中的所有列,如果客户有 3 条记录而供应商有 2 条记录,则返回客户和供应商的所有记录,然后供应商将在所有列中显示 NULL
【讨论】:
【参考方案9】:Select
DISTINCT t1.col,t2col
From table1 t1, table2 t2
OR
Select
DISTINCT t1.col,t2col
From table1 t1
cross JOIN table2 t2
如果它的拥抱数据,它需要很长时间..
【讨论】:
【参考方案10】:SELECT t1.col table1col, t2.col table2col
FROM table1 t1
JOIN table2 t2 on t1.table1Id = x and t2.table2Id = y
【讨论】:
虽然此代码可能会回答问题,但提供有关 why 和/或 如何 它回答问题的额外上下文将显着改善其长期价值。请edit你的答案添加一些解释。【参考方案11】:select * from this_table;
select distinct person from this_table
union select address as location from that_table
drop wrong_table from this_database;
【讨论】:
【参考方案12】:当您必须使用三个选择语句执行此操作时非常困难
我尝试了所有建议的技术,但都是徒劳的
请看下面的脚本。如果您有其他解决方案,请告知
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
【讨论】:
【参考方案13】:加入不相关的表
演示 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;
【讨论】:
【参考方案14】:请试试这个查询:
合并两个没有公共列的表:
SELECT *
FROM table1
UNION
SELECT *
FROM table2
ORDER BY orderby ASC
【讨论】:
这仅适用于两个表具有相同数量的表达式 嗯,它与例外答案几乎相同,在接受的答案中,他们添加了“空”列来绕过这个问题以上是关于合并两个没有公共字段的表的主要内容,如果未能解决你的问题,请参考以下文章
Python pandas:合并两个没有键的表(将 2 个数据帧与广播所有元素相乘;NxN 数据帧)
如何在没有公共密钥的情况下合并 Apache Spark 中的两个数据帧?