简体   繁体   中英

Referencing multiple foreign keys from one table to the same value in another table and reading the value

I am working on an app to create and manage background audio. It is represented by scenes.

Every scene has an intro, a background music and ambience. I have to differ these audio types as in my app they are treated differently and can have own settings. Furthermore, while listing the scenes, I want to display every audio type in current scene by title. In my currenct concept I have to join 3 tables and get a list of titles as result.

Now I´ve been working on a concept, but I am not sure if this is the best way to do that. Maybe could you help me to optimize it.

That is how the database looks like:

CREATE TABLE scene (
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
    title TEXT NOT NULL, 
    intro INTEGER,
    music INTEGER,
    ambience INTEGER,
    FOREIGN KEY (intro) REFERENCES audioInScene(id) ON DELETE CASCADE,
    FOREIGN KEY (music) REFERENCES audioInScene(id) ON DELETE CASCADE,
    FOREIGN KEY (ambience) REFERENCES audioInScene(id) ON DELETE CASCADE);

CREATE TABLE audioOpts (
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    volume INTEGER NOT NULL,
    repeat INTEGER NOT NULL);

CREATE TABLE audioFile (
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    title TEXT NOT NULL,
    path TEXT UNIQUE NOT NULL);

CREATE TABLE audioWithOpts (
    id INTEGER PRIMARY KEY,
    file INTEGER NOT NULL,
    opts INTEGER NOT NULL,
    FOREIGN KEY (file) REFERENCES audioFile (id),
    FOREIGN KEY (opts) REFERENCES audioOpts (id) ON DELETE CASCADE);

CREATE TABLE audioInScene(
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    inScene INTEGER NOT NULL,
    audio INTEGER NOT NULL,
    tag TEXT NOT NULL,
    FOREIGN KEY (inScene) REFERENCES scene (id) ON DELETE CASCADE,
    FOREIGN KEY (audio) REFERENCES audioWithOpts (id) ON DELETE CASCADE
);

And for example, this is a join statement that I have to execute to get the intro title, music title and ambience title:

SELECT scene.title, audioFile.title
FROM scene
INNER JOIN audioInScene ON scene.intro=audioInScene.audio OR scene.music=audioInScene.audio OR scene.ambience=audioInScene.audio
INNER JOIN audioWithOpts ON audioInScene.audio=audioWithOpts.id
INNER JOIN audioFile ON audioWithOpts.file=audioFile.id

And the output looks like:

sceneTitle | introTitle
sceneTitle | musicTitle
sceneTitle | ambienceTitle

How could I create my concept to get output like this

sceneTitle | introTitle | musicTitle | ambienceTitle

You can make use of STRING_AGG in SQL server to achieve this.

select [sceneTitle], STRING_AGG(IntroTitle, ' | ') WITHIN GROUP (ORDER BY IntroTitle) AS IntroTitle
from dbo.table1 group  by [sceneTitle];

One option is to do 3 joins, you can use WITH to remove repetition.

WITH audioMap AS (
  SELECT audioInScene.audio, audioFile.title
  FROM audioInScene
  INNER JOIN audioWithOpts ON audioInScene.audio=audioWithOpts.id
  INNER JOIN audioFile ON audioWithOpts.file=audioFile.id
)
SELECT scene.title, a1.title AS intro, a2.title AS music, a3.title AS ambience
FROM scene
INNER JOIN audioMap a1 ON scene.intro=a1.audio
INNER JOIN audioMap a2 ON scene.music=a2.audio
INNER JOIN audioMap a3 ON scene.ambience=a3.audio

Other option is to use your query and add PIVOT to convert rows to columns based on title.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM