2013-03-04 169 views
2

我正在做一個工會,像這樣SQL UNION刪除「半重複」

select name, price from products where project = 10 // prio 1 
union 
select name, price from products where customer = 5 // prio 2 
union 
select name, price from products where standard = 9 // prio 3 

編輯:改變了where子句,使之更復雜一點

這通常會給我回

+-----+------+-----------+--------------+ 
|(NO) | name | price | (prio)  | 
+-----+------+-----------+--------------+ 
| 1 | a | 10  | (1)   | 
| 2 | b |  5  | (1)   | 

| 3 | a | 13  | (2)   | 
| 4 | b |  2  | (2)   | 

| 5 | a |  1  | (3)   | 
| 6 | b |  5  | (3)   | 
| 7 | c |  3  | (3)   | 
+-----+------+-----------+--------------+ 

我明白,例如第1行和第3行不重複,並且不會被union語句刪除。但是,這正是我想要做的。也就是說,如果第一個select語句(prio 1)返回名稱(例如「a」),我不希望任何其他「a」:從更高優先級的select語句進入結果集。

即,我想這一點:

+-----+------+-----------+--------------+ 
|(NO) | name | price | (prio) | 
+-----+------+-----------+--------------+ 
| 1 | a | 10  | (1)   | 
| 2 | b |  5  | (1)   | 

| 7 | c |  3  | (3)   | 
+-----+------+-----------+--------------+ 

這可能嗎?

我嘗試使用group by但是這需要我使用MIN,MAX,AVG等,關於這一點我不想做的價格,即:

select name, avg(price) from (...original query...) group by name 
// this is not ok since I donnot want the avg price, I want the "first" price 

我使用MS SQL 2000。我可以在group by中使用像first(..)這樣的聚合函數嗎?嘗試此操作時,出現錯誤:

select name, first(price) from (...original query...) group by name 
// error: 'first' is not a recognized built-in function name. 

謝謝!

+1

什麼[RDBMS](http://en.wikipedia.org/wiki/Relational_database_management_system)您使用的? 'RDBMS'代表*關係數據庫管理系統*。 'RDBMS是SQL'的基礎,並且適用於所有現代數據庫系統,如MS SQL Server,IBM DB2,Oracle,MySQL等... – 2013-03-04 09:34:37

+0

@JW。我看到你有一個SQL Server的答案准備好了。它缺少'WHERE prio IN(1,2,3)' – 2013-03-04 09:38:42

+0

@MartinSmith,但我認爲它贏了;在'SQL Server 2000'中工作hehe – 2013-03-04 09:39:22

回答

2

對於SQL Server 2005+:

WITH records 
AS 
(
    SELECT name, price, prio, 
      ROW_NUMBER() OVER (PARTITION BY name 
           ORDER BY prio ASC) rn 
    FROM products 
) 
SELECT Name, Price 
FROM records 
WHERE rn = 1 

嘗試此SQL Server 2000

SELECT a.* 
FROM products a 
     INNER JOIN 
     (
      SELECT name, MIN(prio) min_prio 
      FROM products 
      WHERE prio IN (1,2,3) 
      GROUP BY name 
     ) b ON a.name = b.name AND 
       a.prio = b.min_prio 

要獲得更好的性能,請在列(name, prio)上添加複合索引。

+0

謝謝JW,這看起來棒極了!但是,我很抱歉太簡化了這個問題。如果你不想感到沮喪,那就去看看在探索中的新的where-clause吧:) – Cotten 2013-03-04 09:52:10

1
select name, price from products where prio = 1 
union 
select name, price from products where prio = 2 and name not in (select name from products where prio = 1) 

union 
select name, price from products where prio = 3 and name not in 
(select name from products where prio = 1 
union 
select name from products where prio = 2 and name not in (select name from products where prio = 1)) 
1

不知道這工作,但這個想法是這樣的:

select name, 
    min(case when prio=min_prio then price else NULL end) as price, 
    min(prio) as min_prio 
from products 
group by name 
order by min_prio