首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何设计外键可以表示“所有行”、“一些行”或“一行”的表关系?

如何设计外键可以表示“所有行”、“一些行”或“一行”的表关系?
EN

Stack Overflow用户
提问于 2016-11-17 16:29:41
回答 4查看 53关注 0票数 1

我希望你能帮我解决这个问题。我使用伪代码来使一切变得简单。

我有一个描述位置的表格。

代码语言:javascript
运行
复制
location_table
location = charfield(200) # New York, London, Tokyo

产品经理现在希望位置如下所示:

代码语言:javascript
运行
复制
Global = select every location
Asia = select every location in Asia
US = select every location in US
Current system = London (etc.)

这是我提议的重新设计。

代码语言:javascript
运行
复制
location_table
location = charfield(200) # New York, London, Tokyo
continent = foreign key to continent_table

continent_table
continent = charfield(50) # "None", "Global", Asia, Europe

但这看起来很可怕。这意味着在我的代码中,我总是需要检查客户使用的是"global“还是"none",然后选择相应的位置记录。例如,到处都会有这样的代码:

代码语言:javascript
运行
复制
get continent 
if continent is global, select everything from location_table
else if continent is none, select location from location_table
else select location from location_table where foreign key is continent

我的感觉是这是一个已知的问题,并且有一个已知的解决方案。有什么想法吗?

谢谢。

EN

回答 4

Stack Overflow用户

发布于 2016-11-17 16:41:54

使用级别:

代码语言:javascript
运行
复制
0   -> None
00  -> Global
001 -> Europe
002 -> Asia
003 -> Africa

select location from location_table where continent like '[value]%'

使用固定长度代码,您可以为区域添加前缀,然后为区域内的区域再添加一个数字,依此类推。

好的,让我试着改进一下。

考虑世界,它有最低级别(或最高级别取决于你如何看待它)

代码语言:javascript
运行
复制
World ID = '0' (1 digit)

现在,选择您想要如何划分世界:(大陆,半大陆,...)并指定下一级。

代码语言:javascript
运行
复制
Europe ID  = '01' (First digit World + Second digit Europe)
Asia ID    = '02' 
America ID = '03'
...

下一级:国家。(至少2位数字)

代码语言:javascript
运行
复制
England ID    = '0101' (World + Continent + Country)
Deutchland ID = '0102'
....
Texas ID      = '0301'
....

下一级:区域(2位)

代码语言:javascript
运行
复制
Yorkshire ID = '010101' (World + Continent + Country + Region)
....

下一级:城市(2位或3位)

代码语言:javascript
运行
复制
London ID = '01010101' (World + Continent + Country + Region + City)

诸若此类。

现在,无论哪个区域都可以使用相同的SELECT some_aggregate, statistics, ... FROM ...,只需更改:

代码语言:javascript
运行
复制
WHERE Region like '0%'                        --> The whole world
WHERE Region like '02%'                       --> Asia
WHERE Region like '01010101%'                 --> London
WHERE Region like '02%' AND Region like '01%' --> Asia & Europe
票数 0
EN

Stack Overflow用户

发布于 2016-11-17 16:42:27

您在这里看到的似乎是一组位置,然后是一组位置组。这些组可以是所有位置(全局),也可以是它们的子集。

您可以使用位置之间的中间表和关联位置和位置集的新位置集表来构建此表。

您可以构建位置集表和连接表,以便各个位置也是位置集,但这些位置仅连接到一个位置。这样,所有的位置选择都来自一个表--位置集。

因此,您最终得到了三种不同类型的位置集:

映射1:1的所有("global")

  • Ones映射1:多个(大陆和其他地区)

可以想象,这可以被创建为一个层次结构,但这些查询效率可能很低,因为优化器往往看不到联接基数。

票数 0
EN

Stack Overflow用户

发布于 2016-11-17 17:07:41

您可以使用层次结构和自引用外键来实现这一点,例如

代码语言:javascript
运行
复制
LocationID      Name        ParentLocationID        LocationType
------------------------------------------------------------------
    1        Planet Earth      NULL                 Planet
    2           Africa          1                   Continent
    3         Antartica         1                   Continent
    4           Asia            1                   Continent
    5        Australasia        1                   Continent
    6           Europe          1                   Continent
    7        North America      1                   Continent
    8       South America       1                   Continent
    9       United States       7                   Country
    10         Canada           7                   Country
    11         Mexico           7                   Country
    12      California          9                   State
    13      San Diego           12                  City
    14        England           6                   Country
    15      Cornwall            14                  County
    16        Truro             15                  City

分层数据通常需要递归或多个连接才能获得所有级别,this answer包含比较主要数据库管理系统性能的文章的链接。

许多DBMS现在支持递归公用表表达式,由于没有指定DBMS,因此我将使用SQL Server语法,因为它是我最熟悉的语法,下面是一个简单的示例。

代码语言:javascript
运行
复制
DECLARE @LocationID INT = 7; -- NORTH AMERICA

WITH LocationCTE AS
(   SELECT  l.LocationID, l.Name, l.ParentLocationID, l.LocationType
    FROM    dbo.Location AS l   
    WHERE   LocationID = @LocationID
    UNION ALL
    SELECT  l.LocationID, l.Name, l.ParentLocationID, l.LocationType
    FROM    dbo.Location AS l
            INNER JOIN LocationCTE AS c
                ON c.LocationID = l.ParentLocationID
)
SELECT  *
FROM    LocationCTE;

基于上述示例数据的输出

代码语言:javascript
运行
复制
LocationID  Name            ParentLocationID    LocationType
-----------------------------------------------------------------
7           North America   1                   Continent
9           United States   7                   Country
10          Canada          7                   Country
11          Mexico          7                   Country
12          California      9                   State
13          San Diego       12                  City

为location ID提供值1 (Planet Earth)将返回整个表,或者提供locationID 11 (墨西哥)将仅返回这一行,因为示例数据中没有比这更小的行。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40649951

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档