【问题标题】:Select from multiple tables without cartesian product从没有笛卡尔积的多个表中选择
【发布时间】:2016-02-08 09:58:33
【问题描述】:

我正在尝试创建一个命令,以将客户成员资格的详细信息从一个数据库复制到另一个具有相同结构的数据库。出于问题的目的,我已将其缩减为基本要素,因此要复制的四个项目是到期日期、订阅 ID、客户端 ID 和项目 ID(这是包含订阅的服务)。 客户端在两个基地都有一个共同的 GUID。订阅 ID 是一个唯一的 long int,在两个基数中应该是相同的,并且到期日期只是一个日期。到目前为止,很容易。棘手的部分是 item_id 在每个数据库中不一定相同。我需要使用 where 语句从一个映射到另一个,我知道该怎么做。

我的问题是我需要从目标数据库自己的 ITEM 表 (item_0) 中进行选择,以便获取并插入正确的 item_id,当我这样做时,我会返回数千个重复的行。我认为我需要使用连接来避免这种情况,但由于我没有任何意义来连接 item_0,因此我无法获得任何结果。

insert into DestDB..subscription (expiry_date,id,client_id,item_id)
select 
    sub_1.expiry_date,
    sub_1.id,
    cli_0.id as client_id,
    item_0.id as item_id,
from SourceDB..subscription sub_1,
    DestDB..item item_0,
    DestDB..client cli_0
inner join SourceDB..client cli_1
   on cli_1.[guid] = cli_0.[guid] 
where sub_1.id not in (select id from DestDB..subscription)  
and item_0.id = 
     (select id from DestDB..collectiondetails 
             where service_ID =
              (select id from DestDB..service s_0 where s_0.code = 
                 (select code from SourceDB..service s_1 where s_1.id = 
                    (select service_ID from Source..collectiondetails item_1         where item_1.id = sub_1.item_id)))
             and collection_ID =
               (select id from DestDB..collection col_0
                  where col_0.code = 
                    (select code from SourceDB..collection col_1 where col_1.id =
                       (select collection_ID from SourceDB..collectiondetails item_1 where item_1.id = sub_1.collection_ID)))

     )         

【问题讨论】:

  • DestDB..item和DestDB..client这两个表是怎么连接的,有FK吗?
  • 它们之间没有直接联系。两者都通过 subscription.client_id 和 subscription.item_id 连接到 DestDB.subscription
  • 如果您“没有任何意义加入 item_0”,您希望如何为给定订阅选择正确的项目。一定有什么。否则,您也可以选择一个随机项目。
  • 我不想给出完整的结构,因为它有点复杂,但我想我需要让它更清楚一点! “项目”是项目集合的一部分,该集合存在于两个数据库中,具有单独的 ID,但有一个共同的 CODE 字段。订阅表中的 item_ID 实际上是指该项目在其集合中的 id。
  • 所以 item_ID 1 告诉您查看集合表中的项目 1,您可以在其中找到指向项目本身 ID 的链接。我一直在最后的 where 语句中进行此对决。我会用完整的信息修改它。

标签: sql-server join


【解决方案1】:

恐怕更新后的问题更加令人困惑。 Where 子句中的 Select 是否保证只返回一条记录,还是应该是 in 而不是 =

如果没有从匹配列表中识别特定DestDB..item 的规则,那么顶部的也应该这样做。 item_0 似乎仍然可以完全省略:

insert into DestDB..subscription (expiry_date,id,client_id,item_id)
select 
    sub_1.expiry_date,
    sub_1.id,
    cli_0.id as client_id,
    (select Top 1 id from DestDB..collectiondetails   --<- Limit to top 1 only
             where service_ID =
              (select id from DestDB..service s_0 where s_0.code = 
                 (select code from SourceDB..service s_1 where s_1.id = 
                    (select service_ID from SourceDB..collectiondetails item_1 where item_1.id = sub_1.item_id)))
             and collection_ID =
               (select id from DestDB..collection col_0
                  where col_0.code = 
                    (select code from SourceDB..collection col_1 where col_1.id =
                       (select collection_ID from SourceDB..collectiondetails item_1 where item_1.id = sub_1.collection_ID)))
     ) as item_id,
from SourceDB..subscription sub_1,
    DestDB..client cli_0
inner join SourceDB..client cli_1
   on cli_1.[guid] = cli_0.[guid] 
where sub_1.id not in (select id from DestDB..subscription)  

请注意:如果DestDB..item 为空,则问题示例语句不会插入任何内容,但此答案之一 - 会将item_id 设置为NULL

我个人会尝试在一个事务中将此任务拆分为两个单独的语句:

  1. 使用 NULL item_id 插入目标表。
  2. 使用新的 item_id 更新目标表,其中 item_id 为 NULL。
  3. (可选)在找不到合适的 item_id 时删除不需要的记录。

【讨论】:

  • 见上文。很抱歉最初的问题含糊不清,我试图通过发布太多信息来限制混乱,但我意识到我不清楚。
猜你喜欢
  • 2017-12-14
  • 2021-10-12
  • 2016-06-26
  • 1970-01-01
  • 2021-08-13
  • 2011-12-18
  • 2015-01-15
  • 1970-01-01
  • 2013-07-14
相关资源
最近更新 更多