2016-10-05 148 views
0

鑑於以下(大大簡化)示例表:選擇組合的價值

CREATE TABLE `permissions` (
    `name` varchar(64) NOT NULL DEFAULT '', 
    `access` enum('read_only','read_write') NOT NULL DEFAULT 'read_only' 
); 

而下面的例子內容:

| name | access  | 
===================== 
| foo | read_only | 
| foo | read_write | 
| bar | read_only | 

我想要做的就是運行SELECT查詢爲name中的每個唯一值獲取一行,贊成access值爲read_write,那麼有沒有辦法可以做到這一點?即 - 這樣的結果,我會得到如下:

foo | read_write | 
bar | read_only | 

我可能需要新的選項添加到在未來的access列,但他們將永遠是按重要性順序(從最低到最高),因此,如果可能的話,可以解決這個問題的解決方案將特別有用。另外,爲了澄清,我的實際表格包含了除這些以外的其他字段,這就是爲什麼我在name列中沒有使用唯一密鑰的原因;爲什麼我沒有在name列上使用唯一密鑰?按設計名稱會有多行,以適應各種標準。由字符串值,而不是索引

select name, max(access) 
from permissions 
group by name; 

然而,這個命令:

+0

要做到這一點,最好的方法確實取決於「未來」數據在訪問中的樣子以及您希望返回的內容。例如,除非有「read_write」條目,否則您是否希望訪問按字母順序排序? – kbball

回答

3

以下將您的數據的工作。這是另一種方法:

select name, 
     substring_index(group_concat(access order by access desc), ',') as access 
from permissions 
group by name; 

這是相當時髦的是order by流逝的索引,但min()max()使用字符值。有些人甚至可能稱之爲錯誤。

2

您可以創建另一個表與access的優先級(這樣你就可以添加新的選項),然後按組,並找到MIN()值的優先級表:

例如創造與價值

| PriorityID| access  | 
======================== 
| 1   | read_write | 
| 2   | read_only | 

然後叫Priority表,

SELECT A.Name, B.Access 
FROM (
    SELECT A.name, MIN(B.PriorityID) AS Most_Valued_Option -- This will be 1 if there is a read_write for that name 
    FROM permissions A 
    INNER JOIN Priority B 
    ON A.Access = B.Access 
    GROUP BY A.Name) A 
INNER JOIN Priority B 
ON A.Most_Valued_Option = B.PriorityID 
    -- Join that ID with the actual access 
    -- (and we will select the value of the access in the select statement) 
+0

我不認爲有必要製造龍捲風來吹滅一場比賽。 – spencer7593

+0

您將如何解決'將來'在'access'列添加新選項'的需求? (我擔心新選項不會按照與字母順序匹配的重要性排序) –

+0

如何解決針對不同查詢的不同優先級順序的需求?我擔心訪問的這個「優先級」與* query *相關的​​多於權限。 – spencer7593

0

您可以使用不同的聲明(或一組) 選擇不同的名稱,訪問 由表;

+0

OP可以做到這一點,但'SELECT DISTINCT name,access FROM ...'會返回'name ='foo''的兩行*。它會返回'read_only'和'read_write'。 ('DISTINCT'關鍵字適用於SELECT列表中的* all *表達式。) – spencer7593

0

這工作太:

SELECT name, MAX(access) 
    FROM permissions 
GROUP BY name ORDER BY MAX(access) desc 
1

戈登提出的解決方案足以滿足當前需求。

如果我們預計未來優先級訂單的要求不是按字母順序排序(或按枚舉索引值)......

戈登的回答修改後的版本,我會非常想使用MySQL的FIELD功能(它的逆)ELT功能,這樣的事情:

SELECT p.name 
    , ELT(
     MIN(
      FIELD(p.access 
      ,'read_only','read_write','read_some' 
      ) 
     ) 
     ,'read_only','read_write','read_some' 
    ) AS access 
FROM `permissions` p 
GROUP BY p.name 

如果規範是拉動整個行,而不僅僅是access列的值,我們可以使用內嵌視圖的查詢查找首選access,並且加入回preferences表來拉動全行...

SELECT p.* 
    FROM (-- inline view, to get the highest priority value of access 
     SELECT r.name 
       , MIN(FIELD(r.access,'read_only','read_write','read_some')) AS ax 
      FROM `permissions` r 
      GROUP BY r.name 
     ) q 
    JOIN `permissions` p 
    ON p.name = q.name 
    AND p.access = ELT(q.ax,'read_only','read_write','read_some') 

請注意,此查詢不僅返回具有最高優先級的access,還會返回該行中的任何列的任何列。

使用FIELDELT函數,我們可以實現特定的已知值列表的任意特設排序。不只是按字母排序,還是按枚舉索引值排序。

「優先級」的邏輯可以包含在查詢中,並且不會依賴permissions表中的額外列或任何其他表的內容。

要得到我們所尋找的行爲,只是規定了access優先級,則在FIELD函數中使用的「值列表」,將需要在ELT功能匹配「值列表」,在同訂單,並且列表應該包括所有可能的值access


參考:

http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_elt

http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_field


高級使用

不是說你有一個要求,要做到這一點,但考慮可能的未來要求...我們注意到...

A 不同「值列表」的順序將導致access的優先級的不同順序。因此,各種查詢都可以爲「優先級」實施各自不同的規則。其中access值通過重新排序完整的「值列表」來查找第一,第二等。

不僅僅是重新排序,也可以省略FIELDELT功能「值列表」的可能值。例如,考慮在這條線省略從列表中'read_only'值:

   , MIN(FIELD(r.access,'read_write','read_some')) AS ax 

,並從該行:

AND p.access = ELT(q.ax,'read_write','read_some') 

這將有效地限制name行返回。只有nameaccess值爲'read_write''read_some'。另一種方式看,name只有 a 'read_only'對於access不是被查詢返回。

也可以對列表不匹配的「值列表」進行其他修改,以實現更強大的規則。例如,我們可以排除與'read_only'有一排的name

例如,在ELT函數中,取代'read_only'值,我們使用一個我們知道不存在(也不能)存在於任何行的值。爲了說明這一點,

我們可以包括作爲'read_only'該線路上「最高優先級」 ......

   , MIN(FIELD(r.access,'read_only','read_write','read_some')) AS ax 
            ^^^^^^^^^^^ 

所以如果有'read_only'一行被發現,會被優先。但在外部查詢的ELT功能,我們可以把這一回不同值...

AND p.access = ELT(q.ax,'eXcluDe','read_write','read_some') 
          ^^^^^^^^^ 

如果我們知道'eXcluDe'不在access列中存在,我們已經有效地排除了任何name它有一個'read_only'行,即使有一個'read_write'行。

不是說你有任何規範或目前的要求做任何。需要注意的是將來的查詢具有這些要求。

+0

我標記了Gordon的答案是正確的,因爲它是解決問題的最簡單答案,如上所述。不過,我想感謝你的答案的細節,因爲我實際上發現基於內聯視圖的例子最適合我想解決的實際問題(我想我太簡化了這個問題)。 – Haravikk

+0

@哈拉維克:我同意戈登' – spencer7593