sql - 为一对多表实现查找或插入

标签 sql algorithm postgresql

我有 2 个表,tracklisttrack,其中 tracklist 有很多 tracks。在某些时候,我会收到指向轨道列表的用户输入,我需要创建该轨道列表或返回现有轨道列表(这是因为轨道列表对用户来说是完全透明的)。

我天真的解决方案是找到所有包含 n 轨道的轨道列表,并将 track 加入 tracklist n 次,根据用户输入数据检查每个连接。例如,有 2 个音轨:

SELECT tracklist.id FROM tracklist
  JOIN track t1 ON tracklist.id = t1.tracklist
  JOIN track_name tn1 ON t1.name = tn1.id
  JOIN track t2 ON tracklist.id = t2.tracklist
  JOIN track_name tn2 ON t2.name = tn2.id
 WHERE tracklist.track_count = '20'
   AND (t1.position = 1 AND tn1.name = 'Pancakes' AND t1.artist_credit = '42' AND t1.recording = 1)
   AND (t2.position = 2 AND tn2.name = 'Waffles' AND t2.artist_credit = '9001' AND t2.recording = 2)

但是,这确实不能很好地扩展到大型轨道列表。我非常基本的计时表明,对于 10 个轨道列表,这可能需要 >500 毫秒,而对于具有 100 个轨道的轨道列表,这可能需要大约 7 秒。虽然后者是一种边缘情况,但我使用的任何算法都需要至少能够扩展到这一点。

然而,我仍然坚持使用其他解决方案。我唯一能想到的另一件事是选择所有带有 n 轨道的轨道列表,以及它们的所有轨道,然后在应用程序代码中进行比较。但是,如果可以的话,我真的很想将其保存在数据库服务器上。


这是我正在使用的架构:

CREATE TABLE track
(
    id                  SERIAL,
    recording           INTEGER NOT NULL, -- references recording.id
    tracklist           INTEGER NOT NULL, -- references tracklist.id
    position            INTEGER NOT NULL,
    name                INTEGER NOT NULL, -- references track_name.id
    artist_credit       INTEGER NOT NULL, -- references artist_credit.id
    length              INTEGER CHECK (length IS NULL OR length > 0),
    edits_pending       INTEGER NOT NULL DEFAULT 0,
    last_updated        TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE track_name (
    id                  SERIAL,
    name                VARCHAR NOT NULL
);

CREATE TABLE tracklist
(
    id                  SERIAL,
    track_count         INTEGER NOT NULL DEFAULT 0,
    last_updated        TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

有什么建议吗?

最佳答案

  SELECT DISTINCT tracklist
    FROM track t0
    WHERE 
      (SELECT COUNT(DISTINCT tracklist)
        FROM track t1
          WHERE 
            (
              (t1.id='test1.id')
              OR 
              (t1.id='test2.id')

              ......
              OR 
              (t1.id='testn.id')
            )
      = 1);

  -- This is OK if you have the track ids for this query.
  -- If you do not then you need to replace each of the t1.id='testm.id' statements
  -- with:
  --      t1.recording='testm.recording' AND
  --      t1.tracklist='testm.tracklist' AND
  --      t1.position='testm.position' AND
  --      t1.name='testm.name' AND
  --      t1.artist_credit='testm.artist_credit' AND
  --      t1.length='testm.length' AND
  --      t1.edits_pending='testm.edits_pending' AND
  --      t1.last_updated='testm.last_updated'

由于我的语法可能不完全正确,也没有机会对其进行测试,因此接下来是我要实现的目标的书面描述:

我构建了一个查询,返回您拥有的轨道列表。构建此查询后,我将检查这些轨道的轨道列表是否完全相同。如果是,即查询中只有一个轨道列表,那么这就是您需要的轨道列表。如果查询中没有轨道列表,或者有多个轨道列表,那么您拥有的轨道集不对应于任何一个现有的轨道列表,因此您需要创建一个新的轨道列表。如果证明有必要,此查询不处理实际创建。我不确定它将如何处理退化的情况——查询中根本没有轨道;或者没有列出任何轨道的轨道列表。

关于sql - 为一对多表实现查找或插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5079711/

相关文章:

c# - 没有主键时如何防止使用SqlBulkCopy插入重复记录

arrays - 如何在 m 排序数组中找到一个元素,其中数组的其余部分为零且未给出 m

c++ - 在最佳情况下,QuickSort 算法因堆栈溢出错误而失败 - C++

postgresql - 将查询结果从 BigQuery 导出到 Postgres

python - Postgres 服务器如何知道保持数据库连接打开

PHP 自动完成与 Oracle 错误

c# - 将同一列中的不同值相互附加

sql - 复杂的 SQL 查询字符串内部连接公分母

c# - 有效消除 .NET 表达式树中的公共(public)子表达式

sql - 有人可以帮我指出这个简单的 WHERE 子句有什么问题吗?