2011-07-05 15 views
5

Mam tabelę adresów URL i jeden atrybut jest domeną.Jak mogę wybrać ograniczoną liczbę wierszy o tym samym atrybucie?

Załóżmy, że mam 100 adresów URL od Google, 100 z Facebooka, 100 z Ebay i to samo dla innych domen, ale chcę pobrać 30 pierwszych adresów URL z Google, 30 z Facebooka, 30 z Ebay i 30 z innych ograniczenie do maks. 500 adresów URL.

Jak to zrobić?

+0

Ile domen posiadasz w tym stole? Jeśli masz więcej niż 16, to jak powinno zachowywać się zapytanie? –

+0

Tak, dużo więcej niż 16. Jeśli wybieranie 30 na domenę przekracza maksymalny limit, przestań uzyskiwać więcej adresów URL. Przykład: jeśli limit wynosił 70, uzyskaj 30 od Google, 30 od Facebooka, 10 od Ebay i nikt od innych. –

+1

Jakie domeny powinny mieć preferencje? Jak to się określa? –

Odpowiedz

2

Poniższy SQL postanawia moim przypadku, ale adresy URL są w porządku, ponieważ ROW_NUMBER nie przestrzegają rozkazów. Myślę, że ten SQL wymaga pewnej poprawy.

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

Możesz napisać "PARTION BY BY domain ORDER BY ctid" lub określić inną kolumnę do zamawiania. W każdym razie dobra odpowiedź. –

1

Jak o coś takiego:

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

itp

+0

Proponuję dodanie słowa "WYBIERZ" Google, URL .... WYBIERZ "Facebook", adres URL ... ", aby mógł stwierdzić, skąd pochodzi. – JNK

+0

Ale czy możesz na koniec umieścić LIMIT 70'? –

+1

Możesz zawinąć związki w innym SELECT, a następnie go ograniczyć, jeśli to jest potrzebne – duduamar

1

Moje rozwiązanie w PL/PGSQL oparty. Znalazłem lepszy sposób, że nie potrzebują dodatkowej tabeli tymczasowej (przy użyciu INSERT do tej tabeli w organizmie funkcyjnego), to można użyć tej funkcji, aby prowadzić bezpośrednio:

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'; 

Oto test- dysk:

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); 

Wynik:

 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

Rozumiem, dlaczego napisałeś 'IF 500% 30 <> 0', ale mimo to mnie zachichotał. :) –

+1

+1. Warto zauważyć, że jeśli chcesz, aby domeny były losowo sortowane, możesz użyć domeny "FOR d IN SELECT DISTINCT FROM website LIMIT nrOfDomains ORDER BY RAND()", lub jeśli chcesz, żeby były zamawiane w jakiś inny sposób, czyli miejsce aby to zrobić. –

+0

@Chris Cunningham: Tak, zmieniłem to '500% 30' na bardziej ogólne' totalLimit% singleLimit'. –

Powiązane problemy