簡體   English   中英

如何從多列主鍵中選擇一系列行?

[英]How to select a range of rows from a multiple column primary key?

我試圖在MySQL 5.5中排隊,為了做到這一點,我想選擇兩個主鍵之間的范圍(我可以很容易地得到)。 當主鍵只有一列時,這是微不足道的。 但是,我需要塊的一些表在主鍵中有多個列,我還沒有弄清楚如何在一個預備語句中使這個工作。

這是一個包含一些數據的示例表:

CREATE TABLE test (
  a INT UNSIGNED NOT NULL,
  b INT UNSIGNED NOT NULL,
  c INT UNSIGNED NOT NULL,
  d VARCHAR(255) DEFAULT '', -- various data columns
  PRIMARY KEY (a, b, c)
) ENGINE=InnoDB;

INSERT INTO test VALUES 
(1, 1, 1),
(1, 1, 2),
(1, 1, 3),
(1, 2, 1),
(1, 2, 2),
(1, 2, 3),
(1, 3, 1),
(1, 3, 3),
(2, 1, 1),
(2, 1, 2),
(2, 2, 2),
(2, 3, 1),
(2, 3, 3),
(3, 1, 2),
(3, 1, 3),
(3, 2, 1),
(3, 2, 2),
(3, 2, 3),
(3, 3, 1),
(3, 3, 3);

如果我有兩個主鍵,如(1,1,3)和(3,2,1),則以下語句將起作用。 a1,b1和c1是第一個主鍵的值,a2,b2和c2是第二個主鍵的值:

SELECT * FROM test WHERE a = a1 AND b = b1 AND c >= c1
UNION
SELECT * FROM test WHERE a = a1 AND b > b1
UNION
SELECT * FROM test WHERE a > a1 AND a < a2
UNION
SELECT * FROM test WHERE a = a2 AND b < b2
UNION
SELECT * FROM test WHERE a = a2 AND b = b2 AND c <= c2

要么

SELECT * FROM test WHERE a = 1 AND b = 1 AND c >= 3
UNION
SELECT * FROM test WHERE a = 1 AND b > 1
UNION
SELECT * FROM test WHERE a > 1 AND a < 3
UNION
SELECT * FROM test WHERE a = 3 AND b < 2
UNION
SELECT * FROM test WHERE a = 3 AND b = 2 AND c <= 1

這使

(1, 1, 3),
(1, 2, 1),
(1, 2, 2),
(1, 2, 3),
(1, 3, 1),
(1, 3, 3),
(2, 1, 1),
(2, 1, 2),
(2, 2, 2),
(2, 3, 1),
(2, 3, 3),
(3, 1, 2),
(3, 1, 3),
(3, 2, 1)

但是當第一列相同時,例如(1,2,2)和(1,3,1),上述操作失敗。 在這種情況下,第2和第4 SELECT選擇太多。

SELECT * FROM test WHERE a = 1 AND b = 2 AND c >= 2
UNION
SELECT * FROM test WHERE a = 1 AND b > 2
UNION
SELECT * FROM test WHERE a > 1 AND a < 1
UNION
SELECT * FROM test WHERE a = 1 AND b < 3
UNION
SELECT * FROM test WHERE a = 1 AND b = 3 AND c <= 1

這使

(1, 1, 1), -- erroneously selected from: SELECT * FROM test WHERE a = 1 AND b < 3
(1, 1, 2), -- erroneously selected from: SELECT * FROM test WHERE a = 1 AND b < 3
(1, 1, 3), -- erroneously selected from: SELECT * FROM test WHERE a = 1 AND b < 3
(1, 2, 1), -- erroneously selected from: SELECT * FROM test WHERE a = 1 AND b < 3
(1, 2, 2),
(1, 2, 3),
(1, 3, 1),
(1, 3, 3)  -- erroneously selected from: SELECT * FROM test WHERE a = 1 AND b > 2

期望的輸出是

(1, 2, 2),
(1, 2, 3),
(1, 3, 1)

我想要一個適用於所有主鍵范圍的語句,包括第一列和第二列的相同值。 我還在主鍵中有4列的表,在這種情況下我會擴展模式。

我希望每個表只有一個語句,而不是動態創建查詢,因為查詢將在表格中執行時執行多達一百萬次。 有些表有超過100M的行。

我寧願避免構造多個語句,因為我有數百個要按照這種模式編寫,而寫更多將會更多的工作。 如果這是唯一的選擇,我會這樣做。

我目前使用參數化查詢,並從兩個主鍵以編程方式生成值,在應用程序層中處理所需的重復值(上例中的a1 x3,b1 x2,a2 x3,b2 x2)。 因此,傳遞參數的重復值對我來說很簡單。

我在這一點上最好的猜測是重復SELECTs,WHERE子句的另一部分比較主鍵的列的值。

我會使用此查詢來選擇范圍:

SELECT * 
FROM test
WHERE (a,b,c) >= (1, 1, 3) 
  and (a,b,c) <= (3, 2, 1)

演示: http ://www.sqlfiddle.com/#!2 / d6cf7b / 4


遺憾的是,MySql無法對上述查詢執行范圍優化,請參閱此鏈接: http//dev.mysql.com/doc/refman/5.7/en/range-optimization.html#range-access-single-部分
(章:8.2.1.3.4。行構造函數表達式的范圍優化)
他們說從verion 5.7開始MySql只能優化表單的查詢:

WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ));



基本上上面的查詢等同於這個:

SELECT * 
FROM test
WHERE  
     a = 1 and b = 1 and c >= 3 -- lowest end
     or 
     a = 3 and b = 2 and c <= 1 -- highest end
     or 
     a = 1 and b > 1
     or
     a = 3 and b < 2
     or 
     a  > 1 and a < 3
;

MySql可能會對此查詢形式使用范圍訪問方法優化,請參閱下面的鏈接
(章:8.2.1.3.2。多部分索引的范圍訪問方法):
http://dev.mysql.com/doc/refman/5.7/en/range-optimization.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM