Mysql'de cümle ile birlik ve sipariş kullanma


123

Mysql sorgusunda sendika ile sipariş kullanmak istiyorum. Sitemdeki bir arama için mesafeye dayalı olarak bir tablodan farklı kriterlere göre farklı kayıt türleri alıyorum. İlk seçme sorgusu, tam yer aramayla ilgili verileri döndürür. 2. seçme sorgusu, aranan yere 5 km'lik mesafe ile ilgili verileri döndürür. 3. seçme sorgusu, aranan yere 5-15 km mesafe ile ilgili verileri döndürür.

Ardından, tüm sonuçları birleştirmek ve sayfalandırma ile bir sayfada göstermek için birleşimi kullanarak imgeleyin. Uygun başlık altında 'Kesin arama sonuçları' , '5 km içindeki sonuçlar ' vb.

Şimdi sonuçları id veya add_date'e göre sıralamak istiyorum. Ama sorgumun sonuna cümle ile sıralama eklediğimde (sorgu1 birleşim sorgusu 2 birleşim sorgusu 3 ekleme_tarihine göre sıra). Tüm sonuçları sıralar. Ama istediğim, her başlığın altında sıralanması.


Her tabloda sıralamak istediğiniz alan (lar) ne tür / türler?
user151841

Yanıtlar:


221

Bunu, diğer kriterlerinize göre sıralamadan önce sıralayabileceğiniz her bir seçime rütbe adında bir sözde sütun ekleyerek yapabilirsiniz, örneğin:

select *
from (
    select 1 as Rank, id, add_date from Table 
    union all
    select 2 as Rank, id, add_date from Table where distance < 5
    union all
    select 3 as Rank, id, add_date from Table where distance between 5 and 15
) a
order by rank, id, add_date desc

9
Neden var ave sonu?
Uday Hiwarale

25
MySQL, türetilmiş tabloların bir takma ada sahip olmasını gerektirir.
RedFilter

4
@RedFilter, tam olarak anlamadım. 3 tablonun tümünü seçip sonra bir yapabildiğimizde , "tümünü türetilmiş bir tablo olarak seç" in anlamı nedir order by? ( "tüm UNIONsonucu sıralamak veya sınırlamak için , tek tek SELECTifadeleri parantez içine alın ve sonuncuyu ORDER BYveya LIMITsonrasına yerleştirin" ). Kodunuzu i.stack.imgur.com/LpTMU.png
Pacerier

1
@Pacerier Bu sözdizimi MySQL ile çalışıyorsa, devam edin! Sözdizimim biraz daha çapraz platformdur, genellikle MySQL ile çalışmıyorum. Aslında, daha genel durumlarda çalıştığı için, örneğin, son UNION sorgusundan yalnızca ilk on eşleşmeyi istediğinizde düşünün - yine de sözdizimime geri dönmeniz gerektiğini düşünüyorum.
RedFilter

1
@Pacerier, ayrıca, bu şekilde değerin, görmek istemiyorsanız, sonuçlardan "id, ekle_tarihi seç" ve sonuçlardan "sıralamayı" çıkarmasına olanak tanıyan üst "seçim *" e izin verdiğini de göz önünde bulundurun.
Dev Boş

45

Bunu yapmak için alt sorguları kullanabilirsiniz:

select * from (select values1 from table1 order by orderby1) as a
union all
select * from (select values2 from table2 order by orderby2) as b

1
Tnx, siparişleri ayırmak için iyi. Ayrıca, sipariş maddesi yaygınsa farklı bir düzenlemeye sahip olabiliriz, ancak sonuçların ayrılmasını istiyoruz (siparişleri ayırmak yerine): SELECT * FROM ( SELECT aaa AS Col, 1 AS Official FROM table1 UNION ALL SELECT bbb AS Col, 0 AS Official FROM table2 ) AS tbl ORDER BY Official, Col
Alix

18
Bu yanlış : bireysel ifadeler için kullanımı , satırların nihai sonuçta görünme sırası hakkında hiçbir şey ifade etmezORDER BYSELECT
shmosel

Haklısın, kabul edilen cevap da doğru cevaptır. Bu, test ettiğimde iyi çalıştı.
rickythefox

shmosel (ve rickythefox) - tümünü birleştir, yinelenenleri kaldırmaz ve bu nedenle, ayrı ayrı sıralanmış seçimlerinizin türünü değiştirmek için hiçbir neden yoktur. Geçmişte sizin için işe yaramasının ve gelecekte de sizin için çalışmasının nedeni budur. Nihai sonuçta karışan sipariş, UNION (DISTINCT) 'nin satırları verimli bir şekilde birleştirmek için bir tür sıralamaya ihtiyaç duymasından kaynaklanmaktadır. Veya daha spesifik olarak, satırları verimli bir şekilde birleştirdiği için sıralar. Böylece, alt sorgularınızı korumak için tüm birleşime güvenebilirsiniz.
Gerard ONeill

2
Bu artık bu yaklaşım olacak, eski MySQL sürümleri için büyük çalışıyordu DEĞİL çalışır. Çünkü SQL standardı, alt sorgu sırasını korumayı garanti etmez.
Andrei

28
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 

order by add_date

Bu işe yaradı, ama tuhaf bir şekilde bir şeyi değiştirmem gerekiyordu: Sipariş veren alana paylaşılan bir takma ad vermem gerekiyordu. Bunun yanında çalıştı, teşekkürler!
HoldOffHunger

9

Bir birleşim sorgusu yalnızca bir ana ORDER BYyan tümce, IIRC'ye sahip olabilir. Bunu elde etmek için, daha büyük UNIONsorguyu oluşturan her sorguda , UNION'ler için sıralayacağınız tek alan olacak bir alan ekleyin ORDER BY.

Örneğin, bir şeye sahip olabilirsiniz

SELECT field1, field2, '1' AS union_sort
UNION SELECT field1, field2, '2' AS union_sort
UNION SELECT field1, field2, '3' AS union_sort
ORDER BY union_sort

Bu union_sortalan, sıralamak isteyebileceğiniz herhangi bir alan olabilir. Bu örnekte, ilk olarak ilk tablodan, ikinci tablodan vb. Sonuçlar koyar.


9

Unutmayın, bütün birleştirme, kayıtları bir kayıt kümesine sıralama veya birleştirme olmadan eklemenin bir yoludur (birleşmenin aksine).

Yani mesela:

select * from (
    select col1, col2
    from table a
    <....>
    order by col3
    limit by 200
) a
union all
select * from (
    select cola, colb
    from table b
    <....>
    order by colb
    limit by 300
) b

Tek tek sorguları daha net tutar ve her sorguda farklı parametrelere göre sıralama yapmanızı sağlar. Bununla birlikte, seçilen cevabın yolunu kullanarak, karmaşıklığa ve sıralamayı kavramsallaştırdığınız için verilerin ne kadar ilişkili olduğuna bağlı olarak daha net hale gelebilir. Ayrıca, yapay sütunu sorgulama programına döndürmenize olanak tanır, böylece sıralayabileceği veya düzenleyebileceği bir içeriğe sahip olur.

Ancak bu yol, hızlı olma, fazladan değişkenler getirmeme ve sıralama dahil her sorguyu ayırmayı kolaylaştırma avantajına sahiptir. Limit ekleme yeteneği sadece ekstra bir bonustur.

Ve elbette, birleşimi bir birleşmeye dönüştürmekten ve tüm sorgu için bir sıralama eklemekten çekinmeyin. Veya yapay bir kimlik ekleyin, bu durumda bu şekilde her sorguda farklı parametrelere göre sıralamayı kolaylaştırır, ancak aksi takdirde kabul edilen yanıtla aynıdır.


4

Bunu bir katılma artı birliği üzerinde çalıştırdım.

(SELECT 
   table1.column1,
   table1.column2,
   foo1.column4
 FROM table1, table2, foo1, table5
 WHERE table5.somerecord = table1.column1
 ORDER BY table1.column1 ASC, table1.column2 DESC
)

UNION

(SELECT
    ... Another complex query as above
)

ORDER BY column1 DESC, column2 ASC

3

Bir mysql ORDER BYile birlikte kullanılan bir alt sorgunun içinde bir yan tümce kullandığınızda, yan UNIONtümceyi optimize eder ORDER BY.

Bunun nedeni, varsayılan olarak UNIONa'nın sırasız bir liste döndürmesidir, bu nedenle bir ORDER BYhiçbir şey yapmaz.

Optimizasyon belgelerde belirtilir ve şöyle der:

ORDER BY veya LIMIT'i tek bir SELECT'e uygulamak için, SELECT'i çevreleyen parantezlerin içine tümceyi yerleştirin:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

Ancak, tek tek SELECT deyimleri için ORDER BY kullanımı, satırların nihai sonuçta görünme sırası hakkında hiçbir şey ifade etmez çünkü UNION varsayılan olarak sırasız bir satır kümesi üretir. Bu nedenle, bu bağlamda ORDER BY kullanımı tipik olarak LIMIT ile bağlantılı olduğundan, SELECT için almak üzere seçilen satırların alt kümesini belirlemek için kullanılır, ancak bu satırların içindeki sırayı etkilemeyebilir. final UNION sonucu. ORDER BY bir SELECT'te LIMIT olmadan görünürse, yine de hiçbir etkisi olmayacağı için optimize edilmiştir.

Bunun son cümlesi biraz yanıltıcı çünkü bir etkisi olmalı. Bu optimizasyon, alt sorgu içinde sipariş vermeniz gereken bir durumdayken soruna neden olur.

MySQL'i bu optimizasyonu yapmamaya zorlamak için aşağıdaki gibi bir LIMIT cümlesi ekleyebilirsiniz:

(SELECT 1 AS rank, id, add_date FROM my_table WHERE distance < 5 ORDER BY add_date LIMIT 9999999999)
UNION ALL
(SELECT 2 AS rank, id, add_date FROM my_table WHERE distance BETWEEN 5 AND 15 ORDER BY rank LIMIT 9999999999)
UNION ALL
(SELECT 3 AS rank, id, add_date from my_table WHERE distance BETWEEN 5 and 15 ORDER BY id LIMIT 9999999999)

Yüksek , sayfalandırma gibi bir şey yapmak istiyorsanız genel sorguya LIMITbir ekleyebileceğiniz anlamına gelir OFFSET.

Bu aynı zamanda size ORDER BYher bir birleşim için farklı sütunlar oluşturabilme avantajını da sağlar .


0

Deneyin:

SELECT result.* 
FROM (
 [QUERY 1]
 UNION
 [QUERY 2]
) result
ORDER BY result.id

[QUERY 1] ve [QUERY 2], birleştirmek istediğiniz iki sorgunuz nerede.


0

Bunun nedeni, tüm sonuç kümesini sıralamanızdır, birleşimin her parçasını ayrı ayrı sıralamanız gerekir veya ORDER BY (Bir şey yani alt sorgu mesafesi) THEN (bir şey yani satır kimliği) cümlesini kullanabilirsiniz.


0

Birleştirmeden önce sorguların her birine sıralamayı eklemeyi denedim.

(select * from table where distance=0 order by add_date) 
union 
(select * from table where distance>0 and distance<=5 order by add_date)

ama işe yaramadı. Aslında her seçimden satırlar içinde sıralama yapmadı.

Sanırım dışarıdan sıralamayı tutmanız ve nerede cümlesindeki sütunları sıraya göre eklemeniz gerekecek.

(select * from table where distance=0) 
union 
(select * from table where distance>0 and distance<=5) 
order by distance, add_date

Aralıklara göre gruplamak istediğiniz için bu biraz yanıltıcı olabilir, ancak bence bu yapılabilir.


user151841 aşağıdaki union_sort fikri, gruplamayı halletmek için güzel bir yol olabilir
Mike C
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.