2012-04-25 18 views
8

Bir flört uygulaması için, birleştirilmiş sorguların her ikisi de bir LIMIT 10 ile tek bir çıktı için sorgulamam gereken birkaç tablo var. Onları ayrı ayrı sorgulamak bir sorun olmasa da, şu anda yapmak zor görünüyor, ancak LIMIT 10 numaraları tam olarak çalışmaz (ex LIMIT 5 ve LIMIT 5 değil, bir sorgu 0 satır dönebilir diğer 10 ise senaryoya göre). Bunun yerine burada birleştirilmesi gereken iki sorguları 10 bir LIMIT ile tek sorgudaMySQL - İki seçim ifadesini LIMIT ile verimli bir şekilde bir araya getirme

1. Herb requested a date with you. 
2. Megan wants a platonic relationship with you. 

:

members table 
member_id | member_name 
------------------------ 
    1   Herb 
    2   Karen 
    3   Megan 

dating_requests 
request_id | member1 | member2 | request_time 
---------------------------------------------------- 
    1   1   2  2012-12-21 12:51:45 

dating_alerts 
alert_id | alerter_id | alertee_id | type | alert_time 
------------------------------------------------------- 
    5   3   2  platonic 2012-12-21 10:25:32 

dating_alerts_status 
status_id | alert_id | alertee_id | viewed | viewed_time 
----------------------------------------------------------- 
    4   5   2   0  0000-00-00 00:00:00 

bu 2 öğe görmelisiniz, Karen ve sadece giriş yapmış düşünün:

1. Herb requested a date with you. 
    -> query = "SELECT dr.request_id, dr.member1, dr.member2, m.member_name 
       FROM dating_requests dr 
       JOIN members m ON dr.member1=m.member_id 
       WHERE dr.member2=:loggedin_id 
       ORDER BY dr.request_time LIMIT 5"; 
2. Megan wants a platonic relationship with you. 
    -> query = "SELECT da.alert_id, da.alerter_id, da.alertee_id, da.type, 
         da.alert_time, m.member_name 
       FROM dating_alerts da 
       JOIN dating_alerts_status das ON da.alert_id=das.alert_id 
        AND da.alertee_id=das.alertee_id 
       JOIN members m ON da.alerter_id=m.member_id 
       WHERE da.alertee_id=:loggedin_id AND da.type='platonic' 
        AND das.viewed='0' AND das.viewed_time<da.alert_time 
       ORDER BY da.alert_time LIMIT 5"; 

Yine, bazen bu iki tablo boş olabilir ya da 1 tablo boş olabilir ya da her ikisi de tam olabilir (burada LİMİT 10 devreye girer) ve saate göre sıralanır. Bu görevi verimli bir şekilde gerçekleştirmek için nasıl sorgu alacağınıza dair herhangi bir fikir var mı? Düşünceler, tavsiye, çan, optimizasyonlar açıktır.

+1

İki sorgu tarafından döndürülen sütunlar aynıysa, bunları ['UNION'] (http://dev.mysql.com/doc/refman/5.6/en/union.html) ile birleştirin ve tümünü yapın 'LIMIT' işlevini gerçekleştiren bir dış sorgunun alt sorgusu. Aksi takdirde, ikinci sorgunun uygulanması için gerekli olan 'LIMIT' değerini belirleyebilirsiniz (ilk sorgu tarafından döndürülen kayıtların sayısının 10 eksi kadarı) - bu, sorguları çağırmak için kullandığınız herhangi bir dilde bunu yapmak en kolay yoldur. – eggyal

+0

Beklenen sonuçlarla bir tablo oluşturun. Orada sorunu göreceksin. –

+0

2 seçimin farklı seçim listeleriyle birleştirilmesi mümkün değildir. – vyegorov

cevap

17

Birden çok soruyu UNION ile birleştirebilirsiniz, ancak yalnızca sorgularda aynı sayıda sütun varsa. İdeal olarak sütunlar sadece veri tipinde değil, aynı zamanda anlamsal anlamlarında da aynıdır; ancak, MySQL anlamsallığı umursamaz ve daha genel bir şeye dönüştürerek farklı veri türleri işleyecektir - bu nedenle her bir tablonun farklı anlamlara sahip olması için sütunları aşırı yükleyebilir, daha sonra sizin için hangi anlamın uygun olduğunu belirleyin. seviye kodu (bu şekilde yapmamayı tercih etmese de).

sütun sayısı farklı olduğunda ya da iki sorgulardan verilerini daha iyi/daha az aşırı uyum sağlamak istediğinizde, size SELECT ifadeleri içine kukla edebi sütunları ekleyebilir. Örneğin:

SELECT t.cola, t.colb, NULL, t.colc, NULL FROM t; 
onlar başka yerde NULL (ama sütun adları ilk sorguda geldiğini şunları yapabilirsiniz, böylece hatırlamak öyle ki Hatta bazı sütunlar ikinci tablo için ilk masa ve diğerleri için ayrılmış olabilirdi

,) hepsi orada İsminin sağlamak isteyen:

SELECT a, b, c, d, NULL AS e, NULL AS f, NULL AS g FROM t1 
UNION ALL -- specify ALL because default is DISTINCT, which is wasted here 
    SELECT NULL, NULL, NULL, NULL, a, b, c FROM t2; 
bir UNION operatör ile birleştirerek, daha sonra bu şekilde sizin iki sorgu hizalayarak deneyebilirsiniz

; UNION için LIMIT uygulayarak, hedefinize ulaşmada yakınsınız:

(SELECT ...) 
UNION 
    (SELECT ...) 
LIMIT 10; 

yukarıda sunulan ilk tablodan 10 veya daha fazla kayıt herhangi bir kayıt "dışarı itmek" olacak, yani, kalan tek sorun ikincisinden. Ancak, bunu çözmek için dış sorguda bir ORDER BY kullanabiliriz.

Hepsini bir araya getirirsek: Elbette

(
    SELECT 
    dr.request_time AS event_time, m.member_name,  -- shared columns 
    dr.request_id, dr.member1, dr.member2,    -- request-only columns 
    NULL AS alert_id, NULL AS alerter_id,    -- alert-only columns 
     NULL AS alertee_id, NULL AS type 
    FROM dating_requests dr JOIN members m ON dr.member1=m.member_id 
    WHERE dr.member2=:loggedin_id 
    ORDER BY event_time LIMIT 10 -- save ourselves performing excessive UNION 
) UNION ALL (
    SELECT 
    da.alert_time AS event_time, m.member_name,  -- shared columns 
    NULL, NULL, NULL,         -- request-only columns 
    da.alert_id, da.alerter_id, da.alertee_id, da.type -- alert-only columns 
    FROM 
    dating_alerts da 
    JOIN dating_alerts_status das USING (alert_id, alertee_id) 
    JOIN members m ON da.alerter_id=m.member_id 
    WHERE 
    da.alertee_id=:loggedin_id 
    AND da.type='platonic' 
    AND das.viewed='0' 
    AND das.viewed_time<da.alert_time 
    ORDER BY event_time LIMIT 10 -- save ourselves performing excessive UNION 
) 
ORDER BY event_time 
LIMIT 10; 

Artık bu bölümdeki resultset her kaydı okurken uğraşıyoruz sıranın türünü belirlemek için size kalmış (test önermek request_id ve/veya NULL değerleri için alert_id; alternatif olarak, her kayıt hangi tablodan kaynaklandığını açıkça belirten ek bir sütun ekleyebilir, ancak bu id sütunları NOT NULL olan eşdeğer olmalıdır).

+0

Örnek ve açıklama yumurtalı için teşekkürler. Satır alma işleminin arkasındaki mantık, ORDER BY deyiminde, istek zamanları ve farklı tablolara eklendikleri sırada uyarı saatindedir. Teknik olarak, ilk tablodan 3 kaydın olması, ardından ikinci tablodan 2 kaydın olması, daha sonra da LİMİT 10'a ulaşılana kadar tablolar arasında 1 ileri geri kayıt olması muhtemeldir. – Wonka

+0

@Wonka: Bu, dış sorguda bir 'SİPARİŞ BY' ile bunu başarmanız gerektiği gibi geliyor - bunu anlayamıyorsanız bildirin. – eggyal

+0

Yani: ORDER BY [time_here] LIMIT 10? İçindeki sorgular hakkında, sadece ORDER BY dr.request_time LIMIT 5 ve ORDER BY da.alert_time LIMIT 5? Son sorgunun sorgularımda neye benzeyeceğini bana gösterebilir misin, böylece eminim? – Wonka

İlgili konular