2011-07-05 53 views
5

我有一個URL表和一個屬性是域。我如何選擇具有相同屬性的有限數量的行?

假設我有100個來自谷歌的URL,100個來自Facebook,100個來自易趣,其他域也一樣,但我想從Google搜索前30個網址,來自Facebook的30個來自Ebay,來自其他網站的30個限制爲最多500個網址。

我該怎麼做?

+0

你在該表中有多少個域?如果超過16個,那麼查詢應該如何表現? –

+0

是的,遠遠超過16個。如果選擇每個域超過最大限制30個,請停止獲取更多網址。例如:如果限制爲70,則從Google獲得30個,從Facebook獲得30個,從Ebay獲得10個,並且從其他人獲得10個。 –

+1

哪些域名應該有偏好?這是如何確定的? –

回答

2

下面的SQL解決了我的情況,但網址是無序因爲ROW_NUMBER不遵守命令。我認爲這個SQL需要一些改進。

SELECT url,row_number FROM(
    SELECT url,row_number() OVER (PARTITION BY domain) FROM website 
    WHERE domain IN 
    (SELECT DISTINCT domain FROM link) 
) AS links 
WHERE row_number <= 10 
LIMIT 25 
+0

您可以編寫'PARTITION BY c ORDER BY ctid'或指定其他列進行排序。無論如何,很好的答案。 –

1

怎麼是這樣的:

SELECT url FROM link WHERE domain='Google' LIMIT 30 
UNION 
SELECT url FROM link WHERE domain='Facebook' LIMIT 30 
UNION 
SELECT ... 

+0

我會建議加入'SELECT'Google',url .... SELECT'Facebook',url ...',這樣他就可以知道哪個來自哪裏。 – JNK

+0

但是你可以把'LIMIT 70'放在最後? –

+1

您可以將工會包裝在另一個SELECT中,然後限制它,如果這是需要的 – duduamar

1

我在PL/pgSQL的解決方案爲主。我發現了一個更好的辦法,你不需要額外的臨時表(在函數體使用INSERT到該表),即你可以使用該功能來獲得直接的結果是:

CREATE OR REPLACE FUNCTION getURLs(singleLimit integer, totalLimit integer) 
RETURNS SETOF RECORD AS $$ 
DECLARE 
    dom text; 
    nrOfDomains integer; 
    i integer; 
    lim integer; 
    remainder integer; 
BEGIN 
    nrOfDomains := totalLimit/singleLimit; -- integer division (truncate) 
    remainder := totalLimit%singleLimit; 

    IF remainder <> 0 THEN 
     nrOfDomains := nrOfDomains + 1; 
    END IF; 

    i := 1; 
    FOR dom IN SELECT DISTINCT domain FROM website LIMIT nrOfDomains 
    LOOP 
     IF i = nrOfDomains AND remainder <> 0 THEN 
      lim := remainder; 
     ELSE 
      lim := singleLimit; 
     END IF; 

     RETURN QUERY SELECT * FROM website WHERE domain = dom LIMIT lim; 

     i := i + 1; 
    END LOOP; 
    RETURN; 
END $$ 
LANGUAGE 'plpgsql'; 

下面是一些測試 - 開車:

postgres=> CREATE TABLE website(url text, domain text); 
CREATE TABLE 

postgres=> INSERT INTO website 
    SELECT 'http://' || d.column1 ||'/' || n, d.column1 
    FROM generate_series(1, 100) n CROSS JOIN 
    (VALUES ('google'), ('facebook'), ('ebay')) d; 
INSERT 0 300 

postgres=> SELECT * FROM getURLs(10, 25) website(url text, domain text); 

結果:

 url   | domain 
--------------------+---------- 
http://google/1 | google 
http://google/2 | google 
http://google/3 | google 
http://google/4 | google 
http://google/5 | google 
http://google/6 | google 
http://google/7 | google 
http://google/8 | google 
http://google/9 | google 
http://google/10 | google 
http://facebook/1 | facebook 
http://facebook/2 | facebook 
http://facebook/3 | facebook 
http://facebook/4 | facebook 
http://facebook/5 | facebook 
http://facebook/6 | facebook 
http://facebook/7 | facebook 
http://facebook/8 | facebook 
http://facebook/9 | facebook 
http://facebook/10 | facebook 
http://ebay/1  | ebay 
http://ebay/2  | ebay 
http://ebay/3  | ebay 
http://ebay/4  | ebay 
http://ebay/5  | ebay 
(25 rows) 
+1

我明白你爲什麼寫'IF 500%30 <> 0「,但它讓我笑了起來。 :) –

+1

+1。值得注意的是,如果你想讓這些域被隨機排序,你可以使用'FOR d IN SELECT DISTINCT domain FROM website LIMIT nrOfDomains ORDER BY RAND()',或者如果你想讓它們以某種其他方式排序去做吧。 –

+0

@Chris Cunningham:是的,我將'500%30'改爲更通用的'totalLimit%singleLimit'。 –

相關問題