Bir SQL sorgusu ile birden çok sayı nasıl edinilir?


316

Bu sorguyu nasıl yazacağımı merak ediyorum.

Bu gerçek sözdiziminin sahte olduğunu biliyorum, ama ne istediğimi anlamanıza yardımcı olacak. Çok daha büyük bir sorgu parçası olduğu için bu biçimde ihtiyacım var.

SELECT distributor_id, 
COUNT(*) AS TOTAL, 
COUNT(*) WHERE level = 'exec', 
COUNT(*) WHERE level = 'personal'

Tüm bu tek bir sorguda iade gerekir.

Ayrıca, bir satırda olması gerekir, bu nedenle aşağıdakiler işe yaramaz:

'SELECT distributor_id, COUNT(*)
GROUP BY distributor_id'

1
Bu sorgu düzgün çalıştı mı ?? SELECT distributor_id, COUNT(*) AS TOTAL, COUNT(*) WHERE level = 'exec', COUNT(*) WHERE level = 'personal'
Pratik

Yanıtlar:


690

CASEToplama işlevine sahip bir ifade kullanabilirsiniz . Bu temelde PIVOTbazı RDBMS'deki bir işlevle aynı şeydir :

SELECT distributor_id,
    count(*) AS total,
    sum(case when level = 'exec' then 1 else 0 end) AS ExecCount,
    sum(case when level = 'personal' then 1 else 0 end) AS PersonalCount
FROM yourtable
GROUP BY distributor_id

55
Fantastik, bu inanılmaz. Mükemmel cevap. Burada tökezleyen insanlara bir not. Sayım tüm satırları sayar, toplam bir vaka ifadesiyle kullanıldığında sayımla aynı şeyi yapar.
John Ballinger

1
Mükemmel çözüm! Muhtemelen bu yöntemin çok sayıda tabloyu bir sorguda bir araya getirdiğinizde aynı şekilde iyi çalıştığını belirtmek gerekir, çünkü alt sorguları kullanmak bu örnekte oldukça dağınık olabilir.
Darren Crabb

7
Bu çok zarif çözüm için teşekkürler. Btw, bu TSQL ile de çalışır.
Annie Lagang

6
Neden bu en iyi cevap olmayabilir: her zaman tam bir masa taraması. Bir sayımda alt sorguların veya iç içe sayımların birleşimini düşünün. Bununla birlikte, herhangi bir dizin bulunmadığından, yalnızca tek bir tablo taraması ve çoklu karşılaştırmayı garanti ettiğiniz için bu en iyi seçenek olabilir. @KevinBalmforth
YoYo

1
@JohnBallinger, 'Sayım tüm satırları sayar' - akıllıca COUNTsayar distributor_id. tablonun tüm satırları değil, değil mi?
Istiaque Ahmed

88

Kesin olarak çalışan bir yol

SELECT a.distributor_id,
    (SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
    (SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
    (SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM (SELECT DISTINCT distributor_id FROM myTable) a ;

EDIT:
Neden bu yöntemi kullanmak istemiyorsunuz @ KevinBalmforth performans düşüş ve bunun yerine @ Taryn ♦ 'ın yanıt tercih gerekir. Bunu bırakıyorum ki insanlar seçeneklerini anlayabilsin.


2
Bu, birden çok sayımın nasıl çözüleceğime ve her bir sayının bir sütun olacağı şekilde bunları tek bir SELECT deyiminde çıktılamama yardımcı oldu. Harika çalışıyor - teşekkürler!
Mark

2
Burada verdiklerinizi bir projemde kullanabildim. Şimdi her şey birden çok sorgu yerine tek bir Sorgu içinde. Sayfa, birden çok sorguyla 5-8 saniyeye kıyasla bir saniyeden daha kısa sürede yüklenir. Sevdim. Teşekkürler, Notme.
Wayne Barron

1
Her bir alt sorgu aslında bir dizine isabet ederse, bu işe yarayabilir. Değilse, sum(case...)çözüm düşünülmelidir.
YoYo

1
Farklı bir alternatif olarak, düzeltmeyi yaptığım gibi, group byiç içe bir sorgunun tamamını count(*)@Mihai'ın gösterdiği gibi basit bir kodla değiştirme avantajıyla da kullanabileceğinizi unutmayın.
YoYo

43
SELECT 
    distributor_id, 
    COUNT(*) AS TOTAL, 
    COUNT(IF(level='exec',1,null)),
    COUNT(IF(level='personal',1,null))
FROM sometable;

COUNTyalnızca non nulldeğerleri sayar ve yalnızca koşulunuz karşılandığında DECODEboş olmayan değer döndürür 1.


distributor_idsorgu hangisini gösterecek? Toplamda 1 satır gösterir.
Istiaque Ahmed

OP, cevabımda atlanan sütunda bir gruba sahip.
Majid Laissi

Hayatımı kurtardın, diğer tüm soranlar MySQL'de birden fazla satır döndürdü. Thanks so much
Abner

1
@Abner bu 8 yıl sonra hala yardımcı olur sevindim :)
Majid Laissi

@MajidLaissi evet, sorgu zamanımı bir dakikadan bir saniyeden daha azına değiştirdi. :)
Abner

25

Gönderilen diğer cevaplar üzerine bina.

Bunların her ikisi de doğru değerleri üretecektir:

select distributor_id,
    count(*) total,
    sum(case when level = 'exec' then 1 else 0 end) ExecCount,
    sum(case when level = 'personal' then 1 else 0 end) PersonalCount
from yourtable
group by distributor_id

SELECT a.distributor_id,
          (SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
          (SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
          (SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
       FROM myTable a ; 

Bununla birlikte, performans oldukça farklıdır, bu da veri miktarı arttıkça daha alakalı olacaktır.

COUNTs ile sorgu birden çok tablo tarama yapacağını, hiçbir dizin tablo tanımlanmış varsayarak, TOPLA'ları kullanarak sorgu tek bir tablo tarama yapacağını bulundu.

Örnek olarak, aşağıdaki komut dosyasını çalıştırın:

IF OBJECT_ID (N't1', N'U') IS NOT NULL 
drop table t1

create table t1 (f1 int)


    insert into t1 values (1) 
    insert into t1 values (1) 
    insert into t1 values (2)
    insert into t1 values (2)
    insert into t1 values (2)
    insert into t1 values (3)
    insert into t1 values (3)
    insert into t1 values (3)
    insert into t1 values (3)
    insert into t1 values (4)
    insert into t1 values (4)
    insert into t1 values (4)
    insert into t1 values (4)
    insert into t1 values (4)


SELECT SUM(CASE WHEN f1 = 1 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 2 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 3 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 4 THEN 1 else 0 end)
from t1

SELECT 
(select COUNT(*) from t1 where f1 = 1),
(select COUNT(*) from t1 where f1 = 2),
(select COUNT(*) from t1 where f1 = 3),
(select COUNT(*) from t1 where f1 = 4)

2 SELECT deyimini vurgulayın ve Tahmini Yürütme Planını Görüntüle simgesini tıklatın. İlk ifadenin bir tablo taraması yapacağını ve ikincisinin 4 yapacağını göreceksiniz. Açıkçası bir tablo taraması 4'ten daha iyidir.

Kümelenmiş bir dizin eklemek de ilginçtir. Örneğin

Create clustered index t1f1 on t1(f1);
Update Statistics t1;

Yukarıdaki ilk SELECT, tek bir Kümelenmiş Dizin Tarama gerçekleştirecektir. İkinci SELECT, 4 Kümelenmiş Dizin Araması gerçekleştirir, ancak yine de tek bir Kümelenmiş Dizin Taramasından daha pahalıdır. Aynı şeyi 8 milyon sıralı bir masada denedim ve ikinci SELECT hala çok daha pahalıydı.


23

MySQL için bu kısaltılabilir:

SELECT distributor_id,
    COUNT(*) total,
    SUM(level = 'exec') ExecCount,
    SUM(level = 'personal') PersonalCount
FROM yourtable
GROUP BY distributor_id

1
"group by distributor_id" "bu sorguda gerçekten gerekli miydi? O olmadan da çalışabilir
user1451111

2
@ user1451111 orijinal soru anladım bu yüzden cevap sorunun kendisi bağlıdır
Al-Mothafar

11

Hepsini tek bir sorguda almanız gerekiyorsa, bir bağlantı yapabilirsiniz:

SELECT distributor_id, COUNT() FROM ... UNION
SELECT COUNT() AS EXEC_COUNT FROM ... WHERE level = 'exec' UNION
SELECT COUNT(*) AS PERSONAL_COUNT FROM ... WHERE level = 'personal';

Veya, işlemden sonra yapabilirseniz:

SELECT distributor_id, COUNT(*) FROM ... GROUP BY level;

Her seviye için sayı alırsınız ve toplamı elde etmek için hepsini toplamanız gerekir.


İşlevin UNIONbirden çok örneğini içeren bir rapor oluştururken çok yardımcı olduğu bulundu COUNT(*).
James O

Sonuç gösterir #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') FROM distributors UNION SELECT COUNT() AS EXEC_COUNT FROM distributors WHERE ' at line 1.
Istiaque Ahmed

BİRLİĞİ uygulanmış olan tüm sorgulardan döndürülen sütun sayısı eşit olmalıdır. @IstiaqueAhmed muhtemelen hatanızın arkasındaki sebep budur.
user1451111

Gelecekte bu yanıta rastlayan herkes için bir not. Burada açıklanan 'İşlemden Sonra' tekniği, 'düzey' sütunlarındaki bazı değerler NULL olduğunda soruna neden olabilir. Bu durumda, tüm alt sayıların toplamı toplam satır sayısına eşit olmayacaktır.
user1451111

6

Ben sadece her tabloya A sütununda tanımlamak için bir dize adı ve sütun için bir sayı vermek böyle bir şey yapmak. Sonra hepsini bir araya getirdim, böylece istiflensin. Sonuç bence oldukça - diğer seçeneklerle karşılaştırıldığında ne kadar verimli olduğundan emin değilim ama bana ihtiyacım olanı aldım.

select 'table1', count (*) from table1
union select 'table2', count (*) from table2
union select 'table3', count (*) from table3
union select 'table4', count (*) from table4
union select 'table5', count (*) from table5
union select 'table6', count (*) from table6
union select 'table7', count (*) from table7;

Sonuç:

-------------------
| String  | Count |
-------------------
| table1  | 123   |
| table2  | 234   |
| table3  | 345   |
| table4  | 456   |
| table5  | 567   |
-------------------

1
a query that I created makes ...- bu sorgu nerede?
Istiaque Ahmed

2
tüm tablolara nerede caluse eklenir

3

Bluefeet'in aşağıdakileri kullanarak ek bir nüansla kabul edilen yanıtına dayanarak OVER():

SELECT distributor_id,
    COUNT(*) total,
    SUM(case when level = 'exec' then 1 else 0 end) OVER() ExecCount,
    SUM(case when level = 'personal' then 1 else 0 end) OVER () PersonalCount
FROM yourtable
GROUP BY distributor_id

OVER()() Öğesinde hiçbir şey kullanmamak size tüm veri kümesinin toplam sayısını verecektir.


1

Bence bu senin için de işe yarayabilir select count(*) as anc,(select count(*) from Patient where sex='F')as patientF,(select count(*) from Patient where sex='M') as patientM from anc

ve bunun gibi ilgili tabloları seçip sayabilirsiniz select count(*) as anc,(select count(*) from Patient where Patient.Id=anc.PatientId)as patientF,(select count(*) from Patient where sex='M') as patientM from anc

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.