【问题标题】:Transform/Remove Cross Join in Query转换/删除查询中的交叉联接
【发布时间】:2017-04-16 09:34:28
【问题描述】:

我有这个 MsSql

SELECT k._id,
       coalesce(NULLIF(v1.value,''), NULLIF(v2.value,''), k.name) valueWithFallback,
FROM [Keys] k
INNER JOIN [ProductKeys] pk ON pk.key_id = k._id
INNER JOIN [Products] prod ON pk.product_id = prod._id
AND prod._id IN (2)
CROSS JOIN [Langs] l1
LEFT JOIN [Values] v1 ON k._id = v1.key_id
AND l1._id = v1.lang_id
LEFT JOIN [Values] v2 ON k._id = v2.key_id
AND v2.lang_id = 75
WHERE l1.pp_id IN (7,
                   9)

但我必须在没有Cross Join 的情况下这样做,因为我的情况不允许这样做。我的意思是我不能只使用命令CROSS JOIN 左/内连接。
如何使用左/内连接将其转换为相同的结果?
我发现某处提到 Cross Join 是 Inner Join without Condition 所以我尝试过这样的 Inner。

SELECT [dict_Keys].[_id],
       coalesce(NULLIF([value1].[value], ''), NULLIF([value2].[value], ''), [dict_Keys].[name]) AS [fallBack],
FROM [Keys]AS [dict_Keys]
INNER JOIN ([ProductKeys] AS [Products.ProductKeys]
            INNER JOIN [Products] AS [Products] ON [Products].[_id] = [Products.ProductKeys].[product_id]
            AND [Products.ProductKeys].[product_id] IN (2)) ON [dict_Keys].[_id] = [Products.ProductKeys].[key_id]
LEFT JOIN [Values] AS [value1] ON [dict_Keys].[_id] = [value1].[key_id]
INNER JOIN [Langs] AS [value1.dict_Lang] ON [value1].[lang_id] = [value1.dict_Lang].[_id]
LEFT JOIN [Values] AS [value2] ON [dict_Keys].[_id] = [value2].[key_id]
AND [value2].lang_id = 75
WHERE [value1.dict_Lang].pp_id IN (7,
                                   9)
ORDER BY [value1.dict_Lang].[pp_id],
         [name];

第一个查询是使用 MsSql 的。第二个是由无法产生交叉连接的 Sequelize 生成的,仅提到了左/内连接。

编辑1:
也许一个完全另一个查询可以在这里提供帮助。
所以我想要实现的是导出一些Keys。对于每个 Key 都应该是 Translation,在没有 Translation 的情况下,将发生 Fallback。对于这种情况,coalesce.. 先写英文翻译,如果没有,它只写 KeyName,所以永远不会发生空值。 此密钥与产品相关。 所以我需要一个查询:

// get me the Key Id
SELECT k._id,
// Get me the Value to this Key. If there is none for the Selected Lang get the Default = 75, if this is not as well there wirte just the KeyName
       coalesce(NULLIF(v1.value,''), NULLIF(v2.value,''), k.name) valueWithFallback,
// Get me all Keys
FROM [Keys] k
// Which belongs to this selected Product
INNER JOIN [ProductKeys] pk ON pk.key_id = k._id
// through n:m Table ProductKey
INNER JOIN [Products] prod ON pk.product_id = prod._id
// Selected Product
AND prod._id IN (2)
// for Fallback
CROSS JOIN [Langs] l1
// get me the Value to the selected Lang
LEFT JOIN [Values] v1 ON k._id = v1.key_id
AND l1._id = v1.lang_id
// If null for this selected Language get the Default
LEFT JOIN [Values] v2 ON k._id = v2.key_id
AND v2.lang_id = 75
// The selected Languages in which I want to export
WHERE l1.pp_id IN (7,
                       9)

这实际上适用于带有交叉连接的第一个 MsSql 查询。没有交叉连接的另一个查询可以做同样的结果吗?

编辑2:

表: Key

x---------------------x
|  _Id     |  Name    | 
x----------|----------|
|    1     |     Hello|
|    2     |     Test |
x---------------------x

表: Value

x----------------------------------------x
|  _id  |    key_id   | lang_id| value   | 
x---------|-----------|------------------x            
|    1    |     1     |    73  | Dehello | 
|    2    |     2     |    73  | DeTest  |
x-----------------------------------------x

表: Lang

x---------------------------x
|  _id    |  pp_id    | code| 
x---------|-----------|-----|
|    73   |     7     | de  |  
|    75   |     9     | en  | 
x---------------------------x

使用 cross join 我的结果是:
结果

x-----------------------x
|  key_Id  |  value     | 
x----------|------------|
|    1     |     Hello  |
|    2     |     Test   |
|    1     |     DEHello|
|    2     |     DETest |
x-----------------------x

我得到了属于所选产品的所有密钥(缺少产品表示例,因为我认为问题不在于那里)。按照要求,将所有Valuespp_idLangs TableResultTable as -> DEHello 都给我。如果Value table 中没有value 用于询问pp_id,那么请给我Fallback->coalesceResultTable as -> Hello。我希望这对我的需求有所帮助。
正如霍根的回答要么给了我 all values 而不尊重 pp_id IN(7,9) 要么给我 only values 其中pp_id in (7,9) 存在而不做@ 987654347@.

【问题讨论】:

  • 你可以试试INNER JOIN [Langs] AS [value1.dict_Lang] ON 1=1
  • 不知道什么情况下不允许使用CROSS JOIN,但是如果您需要没有此代码的相同效果,您可以使用SELECT * FROM tblA,tblB .在这两种情况下,您都会得到 笛卡尔积 (each-with-each)。实际上有理由更喜欢CROSS JOIN...
  • 这听起来像是一个非常奇怪的人为要求。 CROSS JOIN 在这里是正确的。
  • @SeanLange -- 不是真的,因为 where 语句 (WHERE l1.pp_id IN...) 它并不是真正的“交叉连接”
  • 我知道是的。但如前所述,Sequelize 不支持它或具有命令交叉连接。问题不是我应该改变还是交叉加入这里更好。它即将在没有命令交叉连接的情况下获得相同的结果。但同样的逻辑。

标签: sql sql-server sql-server-2008 sequelize.js cross-join


【解决方案1】:

根据您下面的 cmets,不想要交叉连接,您想要内部连接。通过将条件添加到 where 语句,您将结果限制为与内部连接相同。运行下面的代码看看我是对的。

SELECT k._id,
       coalesce(NULLIF(v1.value,''), NULLIF(v2.value,''), k.name) valueWithFallback,
FROM [Keys] k
INNER JOIN [ProductKeys] pk ON pk.key_id = k._id
INNER JOIN [Products] prod ON pk.product_id = prod._idAND prod._id IN (2)
INNER JOIN [Values] v1 ON k._id = v1.key_id 
INNER JOIN [Langs] l1 ON l1._id = v1.lang_id and l1.pp_id IN (7, 9)
LEFT JOIN [Values] v2 ON k._id = v2.key_id AND v2.lang_id = 75

回到我们在 cmets 中的误解——我的查询将 [Langs] 表限制为 7 和 9——但它没有将其他表限制为 7 和 9——这是内连接 - 将其他表限制为仅包括连接到您的表的行是内连接。交叉连接与此完全相反。显然(正如我一直在说的那样)您不希望使用交叉连接的功能,因此您不应该尝试“使交叉连接工作​​”。


原答案

SELECT k._id,
       coalesce(NULLIF(v1.value,''), NULLIF(v2.value,''), k.name) valueWithFallback,
FROM [Keys] k
INNER JOIN [ProductKeys] pk ON pk.key_id = k._id
INNER JOIN [Products] prod ON pk.product_id = prod._idAND prod._id IN (2)
LEFT JOIN [Values] v1 ON k._id = v1.key_id 
LEFT JOIN [Langs] l1 ON l1._id = v1.lang_id and l1.pp_id IN (7, 9)
LEFT JOIN [Values] v2 ON k._id = v2.key_id AND v2.lang_id = 75

【讨论】:

  • 这似乎不尊重l1.pp_id IN (7,9),因为它加入了每个Langs,而不仅仅是pp_id 7/9
  • @AkAk47 你是说你的平台没有正确处理这个?
  • 结果错误。通过我的交叉查询,我只得到带有所选语言的值的键。使用您的代码,它为选定的键提供了每种语言的每个值,而不仅仅是选定的值。所以我认为它没有正确检查l1.pp_id IN (7,9)?也许我的编辑给了你一个我真正想要实现的暗示。
  • 对不起,我没有收到您更新答案的通知。目前,您的查询似乎朝着正确的方向前进,但仍然缺少include/JOIN-> NULL Values,因此使用 Coalesce 的后备功能不起作用。但是正如我所看到的,您想说我无法通过使用Inner Join 或类似的连接来获得Cross Join 的“功能”?
  • 我也在希望它们更能代表我的问题中对表格示例进行了第二次编辑。如果不能完全理解,请发表评论,我会尝试改变它。
猜你喜欢
  • 2020-09-24
  • 2011-11-06
  • 2012-12-31
  • 2019-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-29
  • 1970-01-01
相关资源
最近更新 更多