棘手的SQL包括外连接和案例

时间:2011-04-02 08:00:37

标签: sql-server-2008 case outer-join

我使用来自http://geonames.org的数据。表结构如下:

GN_Name 1 - 0:N GN_AlternateName

它们链接在:

(PK)GN_Name.GeoNameId == (FK)GN_AlternateName.GeoNameId

GN_Name是包含所有地名的主表。 GN_AlternateName包含其他语言的名称(如果有)。

EX:

GN_Name.Name                   - Stockholm

GN_AlternateName.AlternateName - Estocolmo (if IsoLanguage=="es")

规则:

  • 我想使用GN_AlternateName.AlternateName,如果它存在于指定的语言,并且它是以搜索字符串开头的。

  • 如果没有,我想使用GN_Name.Name,如果它以搜索字符串开头。

  • 我希望GeoNameId是唯一的。

基本上我只能加入第一个记录,但这似乎会降低性能。

我有以下SQL(基本上是从LINQ查询中修改过的SQL)。问题是如果搜索字符串以“stock”开头,它只会找到'Estocolmo'。 “estoc”没有产生任何结果。

select 
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%') 
    THEN an.AlternateName
    ELSE n.Name 
END AS [The name we are going to use]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE n.Name like N'estoc%'

更新

感谢Rahul和Lee D.

我现在有以下内容:

select 
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%') 
    THEN an.AlternateName
    ELSE n.Name 
END AS [The final name]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE (n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%')

这在an.AlternateName上执行两次LIKE。有什么办法可以摆脱LIKE条款吗?

更新2 Andriy M使用COALESCE做了一个不错的替代查询。我改变了一点,结果如下:

SELECT Id, LocalisedName
FROM (
  SELECT
    n.GeoNameId AS Id,
    an.IsoLanguage,
    COALESCE(an.AlternateName, n.Name) AS LocalisedName
  FROM n
    LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
    AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'

此查询完全符合我的要求。谢谢!

3 个答案:

答案 0 :(得分:2)

这是问题的可能解决方案,它采用了稍微不同的方法:

SELECT Id, LocalisedName
FROM (
  SELECT
    n.GeoNameId AS Id,
    an.IsoLanguage,
    COALESCE(an.AlternateName, n.Name) AS LocalisedName
  FROM GN_Name AS n
    LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
      AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'

(根据您的更新进行了更改。)

答案 1 :(得分:0)

如果我理解正确,在您的示例中,值'Estocolmo'位于GN_AlternateName.AlternateName列中,因此将由where子句过滤掉,该子句仅查看GN_Name.Name。如果将SQL的最后一行更改为:

,该怎么办?
WHERE n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%'

我假设'estoc%'是你的搜索字符串。

答案 2 :(得分:0)

我想你需要修改WHERE子句来检查GN_AlternateName

WHERE n.Name like N'estoc%' OR an.AlternateName like 'N'estoc%'