2017-08-31 85 views
3

我在做什麼?

我在使用Electron在JavaScript中編寫文件標記程序,我想使用SQLite。儘管如此,我無法弄清楚如何實現通過標籤進行搜索。我不熟悉SQL和SQLite,所以我不確定這完全可以通過查詢來完成。我如何去搜索如下所述?如何在SQLite中進行高級查詢以通過標籤搜索文件?

檢索詳情:

我看了一下FTS3/4。除了通配符搜索外,我可以做任何我想要的東西。

  • 搜索與所有指定標記的文件:blue_sky AND green_grass
  • 搜索文件而不給出標籤:NOT blue_sky AND NOT green_grass
  • 搜索文件與一些給出標籤:green_sky OR blue_sky
  • 使用通配符搜索文件在標籤中:上述的*sky AND *grass AND *bl*e*
  • 組合:blue_sky AND green*/green_grass AND blue_sky OR green_sky

表:

可以改變

CREATE TABLE files (
    id INTEGER PRIMARY KEY, 
    name TEXT 
); 

CREATE TABLE tags (
    id INTEGER PRIMARY KEY, 
    name TEXT 
); 

CREATE TABLE file_tags (
    id INTEGER PRIMARY KEY, 
    file_id INTEGER, 
    tag_id INTEGER 
); 

實例:

INSERT INTO files (name) VALUES ('file_1.png'); 
INSERT INTO files (name) VALUES ('file_2.png'); 
INSERT INTO files (name) VALUES ('file_3.png'); 
INSERT INTO files (name) VALUES ('file_4.png'); 

INSERT INTO tags (name) VALUES ('blue_sky'); 
INSERT INTO tags (name) VALUES ('green_sky'); 
INSERT INTO tags (name) VALUES ('green_grass'); 
INSERT INTO tags (name) VALUES ('blue_grass'); 
INSERT INTO tags (name) VALUES ('greenish_blue_sky'); 


INSERT INTO file_tags (file_id, tag_id) VALUES(file1_id, blue_sky_id); 
INSERT INTO file_tags (file_id, tag_id) VALUES(file1_id, green_grass_id); 

INSERT INTO file_tags (file_id, tag_id) VALUES(file2_id, blue_sky_id); 
INSERT INTO file_tags (file_id, tag_id) VALUES(file2_id, blue_grass_id); 

INSERT INTO file_tags (file_id, tag_id) VALUES(file3_id, greenish_blue_sky_id); 

INSERT INTO file_tags (file_id, tag_id) VALUES(file4_id, green_sky_id); 
INSERT INTO file_tags (file_id, tag_id) VALUES(file4_id, blue_grass_id); 

查詢:blue_sky and green_grass
結果:file_1

查詢:blue_sky or green_sky
結果:file_1, file_2, file_4

查詢:blue_sky and green_grass or blue_grass
結果:file_1, file_2

查詢:*ish*
結果:file_3

查詢:*bl*e*
結果:file_1, file_2, file_3, file_4

查詢:*sky and not blue_grass
結果:file_1, file3

注意:如果SQLite是不是因爲工作的工具,我很開放的建議。

+0

通配符搜索可以通過使用'LIKE'來實現:https://www.tutorialspoint.com/sqlite/sqlite_like_clause.htm – juzraai

+0

我不確定關於sqlLite,因爲我不使用它。你的數據庫設計很好。它將使您能夠達到您的既定目標。我認爲是一個注意吸氣劑是你使用JavaScript的意圖。它運行在客戶端上。數據庫通常位於服務器上。也許Electron解決了這個問題。我不知道這是什麼,所以我不能說。 –

+0

@juzraai我嘗試過'LIKE',但我不確定如何使用它來構造一個查詢,以滿足我的其他條件。 – Yuki

回答

1

在我看來,您可以通過修改數據庫結構來簡化操作。
例如

  • 使用 '的file_id' 在這兩種情況下
  • 使用外鍵 'TAG_ID' 一致,
    而不是有時 'ID'(誠然,可能需要一個不可用的功能)

你可能在前幾種情況下,能夠使用tag_ids作爲inpit,具體取決於鍵的來源(當然,「一個非常用戶」當然會輸入顏色)。這也會降低錯別字的風險。

所以,你可以做的是:在「file_tags」表

  • 使用連接,
    一個你想要在你的邏輯中使用的每個標籤
  • 加入文件表,訪問文件名字輸出
  • 使用子查詢使用,而不是標籤ID 或使用標籤名稱更加入,而不是,我證明都低於
  • 相當直接複製搜索邏輯到「其中」
  • 組通過的文件名,爲了得到每一個文件根據您不錯的MCVE只有一次

,這裏是你的榜樣查詢建議:

select fs.name from file_tags t1 
     inner join file_tags t2 on t1.file_id = t2.file_id 
     inner join files fs on fs.id = t1.file_id 
where t1.tag_id = (select id from tags where name = 'blue_sky') 
    and t2.tag_id = (select id from tags where name = 'green_grass') 
group by fs.name; 

select fs.name from file_tags t1 
     inner join file_tags t2 on t1.file_id = t2.file_id 
     inner join files fs on fs.id = t1.file_id 
where t1.tag_id = (select id from tags where name = 'blue_sky') 
    or t2.tag_id = (select id from tags where name = 'green_sky') 
group by fs.name; 

-- note, here I had to derive from your desired output 
-- that you want a '()' around the 'or' 
select fs.name from file_tags t1 
     inner join file_tags t2 on t1.file_id = t2.file_id 
     inner join file_tags t3 on t1.file_id = t3.file_id 
     inner join files fs on fs.id = t1.file_id 
where t1.tag_id = (select id from tags where name = 'blue_sky') 
and (t2.tag_id = (select id from tags where name = 'green_grass') 
    or t3.tag_id = (select id from tags where name = 'blue_grass') 
    ) 
group by fs.name; 

select fs.name from file_tags t1 
     inner join files fs on fs.id = t1.file_id 
     inner join tags ts on ts.id = t1.tag_id 
where ts.name like '%ish%' 
group by fs.name; 

select fs.name from file_tags t1 
     inner join files fs on fs.id = t1.file_id 
     inner join tags ts on ts.id = t1.tag_id 
where ts.name like '%bl%e%' 
group by fs.name; 

select fs.name from file_tags t1 
     inner join files fs on fs.id = t1.file_id 
     inner join tags ts on ts.id = t1.tag_id 
where ts.name like '%sky' and not ts.name = 'blue_grass' 
group by fs.name; 

select name from file_tags t1 
     inner join files fs on t1.file_id = fs.id 
where (select name from tags where id = t1.tag_id) like "%sky" 
and not file_id in 
     (select file_id from file_tags 
     where tag_id = (select id from tags where name = 'blue_grass') 
     ); 

輸出:

name 
---------- 
file_1.png 
name 
---------- 
file_1.png 
file_2.png 
file_4.png 
name 
---------- 
file_1.png 
file_2.png 
name 
---------- 
file_3.png 
name 
---------- 
file_1.png 
file_2.png 
file_3.png 
file_4.png 
name 
---------- 
file_1.png 

如果我另外加上:

INSERT INTO tags (name) VALUES ('greenish_blue_sky'); 
INSERT INTO file_tags (file_id, tag_id) VALUES(file3_id, greenish_blue_sky_id); 

然後最後的輸出部分是:

name 
---------- 
file_1.png 
file_3.png 

使用SQLite 3.18.0

+0

我的答案比刪除文件擴展名的編輯稍舊(儘管發佈日期更近)。它不會更改查詢代碼。 – Yunnosch

+0

謝謝,這是一個非常好的答案。乍一看,它看起來正是我需要的東西。我將不得不花費這些查詢來詳細瞭解它們。但有一件事。在最後一個例子中,我期望文件1和3,而不是1,2和4.它看起來像你的查詢應該產生我期望的輸出。我不明白爲什麼沒有。 – Yuki

+0

我沒有注意到(不能說爲什麼)。原因是兩種檢查都是在每個標籤上進行,而不是在一個組合上。加入file_tags兩次需要看兩者。我會稍後修復(從現在開始大約6小時)。 – Yunnosch