2013-06-15 15 views
7

की गणना करें मैं विशिष्ट तालिका के लिए छात्र तालिका से पुरुष, महिला और कुल छात्रों की गणना करना चाहता हूं। मैं चाहता हूँ कि अगर परिणाम के रूप में प्रदर्शित किया जा सकता है: अगर वहाँ निर्दिष्ट वर्ष के लिए कोई पुरुष/महिला मिलान हैपुरुष, महिला और कुल

==================================== 
| Label | Value | Year  | 
==================================== 
| Male  | 0  | 2013  | 
| Female | 23  | 2013  | 
| Total | 23  | 2013  | 
==================================== 

क्वेरी 0 प्रदर्शित करना चाहिए। कोई विचार है कि मैं इसे कैसे कर सकता हूं?

अग्रिम

+0

शायद तुम DDL और अपने वर्तमान प्रदान कर सकते हैं क्वेरी? – Nikola

+0

छात्र तालिका (आईडी, नाम, लिंग, पंजीकृत वर्ष) – aby

+0

आपके लिए चुनने के लिए कई अलग-अलग विकल्प :) क्या आप सिर्फ एसक्यूएल से प्यार नहीं करते हैं! – KyleK

उत्तर

8

धन्यवाद क्वेरी निम्नलिखित पर विचार करें:

select 
    max(registeredYear) as year, 
    count(case when gender='Male' then 1 end) as male_cnt, 
    count(case when gender='Female' then 1 end) as female cnt, 
    count(*) as total_cnt 
from student 
where registeredYear = 2013 
group by registeredYear; 

परिणाम इस तरह होगा:

Year male_cnt female_cnt total_cnt 
---- -------- ---------- --------- 
2013  0   23  23 

आप प्रपत्र आप चाहते हैं करने के लिए इस परिणाम बदल सकता है। आप एक प्रश्न के भीतर यह करने के लिए चाहते हैं, तो आप इसे इस प्रकार कर सकते हैं:

with t as (
    select 
     max(registeredYear) as year, 
     count(case when gender='Male' then 1 end) as male_cnt, 
     count(case when gender='Female' then 1 end) as female cnt, 
     count(*) as total_cnt 
    from student 
    where registeredYear = 2013 
    group by registeredYear) 
select 'Male', male_cnt as male, year from t 
union all 
select 'Female', female_cnt as male, year from t 
union all 
select 'Total', total_cnt as male, year from t 
; 
+0

प्रतिक्रिया के लिए धन्यवाद। लेकिन, जब मैं वर्ष बदलता हूं, तो यह कुछ भी वापस नहीं करेगा, 2014 कहें, जहां कोई डेटा नहीं है। मैं 2014 की उम्मीद कर रहा था। 0 | 0 | 0 – aby

+0

@aby 'count()' फ़ंक्शन हमेशा नंबर लौटाएगा। इस मामले में जहां कोई डेटा नहीं है जो कहां स्थितियों को पूरा करता है, तो यह '0' वापस आ जाएगा। लेकिन साल का हिस्सा खाली होगा ... – ntalbs

+0

@aby शायद आप 'coalesce()' फ़ंक्शन और बाइंड वैरिएबल जैसे 'max (coalesce (registeredYear,: inputYear)) '... का उपयोग कर सकते हैं, जहां' input_year' बाध्य चर है आपको निर्दिष्ट करना चाहिए। मुझे यकीन नहीं है कि SQL सर्वर बाइंड वैरिएबल का उपयोग कैसे करता है, लेकिन आप उसे जान लेंगे। – ntalbs

0

बस इस क्वेरी चलाने ...

SELECT 
    MAX(registeredYear) as Year 
    ,SUM(CASE WHEN gender = 'Male' THEN 1 END) AS Male 
    ,SUM(CASE WHEN gender = 'Female' THEN 1 END) AS Female 
    ,SUM(CASE WHEN gender IS NOT NULL THEN 1 ELSE 0 END) AS Total 
FROM from student 
WHERE registeredYear = 2013 
GROUP BY registeredYear; 
0

कुछ इस तरह:

select 'Male' as Label, count(gender) as Value from student where gender= 'Male' 
union (
select 'Female' as Label, count(gender) as Value from student where gender= 'Female') 
union (
select 'Total' as Label, count(gender) as Value from student) 
+0

यह क्वेरी तालिका को तीन बार पढ़ेगी जो अक्षम है। – ntalbs

0

इसे आज़माएं, लिंग या पंजीकृत में कोई नल मानें:

WITH AllYears AS 
(
    SELECT RegisteredYear 
    FROM Student 
    GROUP BY RegisteredYear 
) 

, AllGenders AS 
(
    SELECT Gender 
    FROM Student 
    GROUP BY Gender 
)  

, AllGendersAndYears AS 
(
    SELECT Gender, RegisteredYear 
    FROM AllGenders, AllYears 
) 

SELECT Gender, RegisteredYear, CountForGenderAndYear 
FROM AllGendersAndYears 
    CROSS APPLY 
    (
     SELECT COUNT(*) AS CountForGenderAndYear 
     FROM Student 
     WHERE Student.Gender = AllGendersAndYears.Gender 
     AND Student.RegisteredYear = AllGendersAndYears.RegisteredYear 
    ) countForGenderAndYear 

UNION ALL 

SELECT 'Total', AllYears.RegisteredYear, CountForYear 
FROM AllYears 
    CROSS APPLY 
    (
     SELECT COUNT(*) AS CountForYear 
     FROM Student 
     WHERE Student.RegisteredYear = AllYears.RegisteredYear 
    ) countForYear 
+0

ओह, यह तालिका में प्रत्येक वर्ष के लिए सारांश मिलता है। आप एक विशिष्ट वर्ष चाहते हैं। ऐसा करने के लिए, AllYears को 'AllYears AS (SELECT 2014 AS RegisteredYear) के रूप में बदलें' –

+0

धन्यवाद, आपका समाधान बहुत करीब है। लेकिन मुझे क्या बदलना चाहिए ताकि महिला | 0 | 2014, पुरुष | 0 | 2014, कुल | 0 | 2014 वापस लौटाया जाएगा जब चयनित वर्ष के लिए कोई डेटा वापस नहीं किया जाएगा? – aby

+0

आह, मैंने पहले लिंग/वर्ष की गणना के साथ एक ही गलती की थी (अगर कोई भी '1' वापस नहीं आया) लेकिन मैंने अब इसे उसी तरह हल किया है। –

0

UNPIVOT का उपयोग करके, एक और भिन्नता है। यह विशेष रूप से केवल पुरुष और महिला की खोज करता है, इसलिए यह मेरे दूसरे के रूप में लचीला नहीं है (क्योंकि आपको प्रत्येक लिंग को हार्डकोड करने की आवश्यकता है)। लेकिन यह शायद सबसे कुशल है।

WITH AllYears (RegisteredYear) AS 
(
    --SELECT DISTINCT RegisteredYear 
    --FROM Student 

    --...OR... 

    SELECT 2014 
) 
, GenderAndYearCounts AS 
(
    SELECT RegisteredYear 
     , SUM(CASE Gender WHEN 'MALE' THEN 1 ELSE 0 END) MaleCount 
     , SUM(CASE Gender WHEN 'FEMALE' THEN 1 ELSE 0 END) FemaleCount 
     , COUNT(*) YearCount 
    FROM Student 
    GROUP BY RegisteredYear 
) 
, GenderAndYearCountsForAllYears AS 
(
    SELECT AllYears.RegisteredYear 
     , ISNULL(MaleCount, 0) AS MaleCount 
     , ISNULL(FemaleCount, 0) AS FemaleCount 
     , ISNULL(YearCount, 0) AS YearCount 
    FROM AllYears 
     LEFT JOIN GenderAndYearCounts ON GenderAndYearCounts.RegisteredYear = AllYears.RegisteredYear 
) 

SELECT Label, Value, RegisteredYear 
FROM 
(
    SELECT RegisteredYear, MaleCount AS Male, FemaleCount AS Female, YearCount AS Total 
    FROM GenderAndYearCountsForAllYears 
) allCounts 

UNPIVOT 
(
    Value FOR Label IN (Male, Female, Total) 
) unpivotted 
0

सभी लिंग, तो सभी वर्ष, तो मायने रखता है:

declare @Year int 
set @Year = 2014 

select labels.label, 
    counts.cnt, 
    @Year as registeredYear 
    from 
     (select 'Male' as label, 1 as sortOrder 
     union all 
     select 'Female', 2 
     union all 
     select 'All', 3) as labels 
    left join 
     (select gender, 
     count(1) cnt 
     from student 
     where registeredYear = @Year 
     group by gender) as counts 
    on labels.label = counts.gender  
    order by labels.sortOrder 
1

मेरा मानना ​​है कि इस बारे में के रूप में कुशल है के रूप में आप सिर्फ साथ प्राप्त कर सकते हैं छात्र तालिका के माध्यम से एक एकल पास। आवश्यकता के अनुसार वर्ष सीटीई में साल बदलें।

with 
year as 
(
    select '2013' year 
), 
gender as (
    select 'Male' gender 
    union all 
    select 'Female' gender 
) 
select coalesce(g.gender,'Total') "Label", 
     count(s.gender) "Value", 
     y.year "Year" 
    from gender g 
    cross join year y 
    left join student s 
    on s.gender = g.gender 
    and s.year = y.year 
group by grouping sets((g.gender, y.year), (y.year)) 
order by case g.gender when 'Male' then 1 when 'Female' then 2 else 3 end 
; 

एक पूरी तरह से सामान्यीकृत डेटा मॉडल में स्कूल वर्ष और लिंग तालिका दोनों की संभावना होगी, इसलिए सीटीई की आवश्यकता नहीं होगी। (जब तक कि आप वास्तव में उन वर्षों तक पंक्तियां वापस नहीं करना चाहते हैं जिनके पास कोई डेटा नहीं है)

यहां एक बेयर-हड्डियां sqlfiddle छात्र आईडी और नाम के बिना प्रदर्शन है क्योंकि वे हाथ में समस्या के लिए अपरिहार्य हैं।

1

आपका अनुरोध बहुत आसान लगता है, लेकिन इसमें दो जटिलताएं हैं। पहला यह है कि एक पंक्ति दूसरे दो का सारांश है। यह क्वेरी में rollup या grouping sets का उपयोग करने का सुझाव देता है।

दूसरा आपके पास कोई डेटा होने पर मूल्य होने की आवश्यकता है। यह "ड्राइवर" सबक्वायरी के उपयोग का सुझाव देता है। इस तरह की एक सबक्वायरी मूल्यों को आवंटित करने से पहले आउटपुट में सभी पंक्तियों को परिभाषित करती है। आप left outer join के साथ ड्राइवर तालिका का उपयोग करते हैं।

एक अस्थिर आवश्यकता केवल एक वर्ष का उल्लेख करने के लिए हो सकती है।

क्वेरी के लिए निम्नलिखित दृष्टिकोण वर्ष के लिए अंतिम रूप को एक साथ रखता है। फिर बाएं, सारांश में शामिल किसी भी अगर वहाँ से मूल्यों को खींच:

with year as (
     select 2013 as Year 
    ) 
select driver.label, coalesce(s.value, 0) as Value, driver.Year 
from ((select 'Male' as label, year from year 
    ) union all 
     (select 'Female' as label, year from year 
    ) union all 
     (select 'Total' as label, year from year 
    ) 
    ) driver left outer join 
    (select coalesce(Gender, 'Total') as Gender, year.year, count(*) as value 
     from Students cross join year 
     group by Gender with Rollup 
    ) s 
    on driver.year = s.year; 

मतलब यह है कि लिंग के रूप में "पुरुष" और "महिला" का प्रतिनिधित्व करती है और वहाँ एक स्तंभ डेटा में year कहा जाता है (नमूना इनपुट के बिना यह है कि या टेबल स्वरूपों को कॉलम नामों और नमूना मानों पर अनुमान लगाना पड़ता है)।

+0

मुझे आपकी व्याख्या पसंद है, लेकिन आपका कार्यान्वयन खराब है और मुझे लगता है कि अत्यधिक जटिल है। "एस" उप-क्वेरी समूह से वर्ष गायब है और कुल मिलाकर सभी वर्षों में गलत है। बाहरी जॉइन स्थिति driver.gender मौजूद नहीं है (driver.label होना चाहिए), और कुल पंक्ति वर्ष (2013 बनाम शून्य) से कभी मेल नहीं खाती है। एक सरल कामकाजी क्वेरी के लिए [मेरा पिछला उत्तर] (http://stackoverflow.com/a/17119899/1012053) देखें। – dbenham

+0

@ डेबेनहम। । । जब मैंने जवाबों को देखा, तो मैं उस व्यक्ति की तलाश कर रहा था जिसमें 'यूनियन' और 'रोलअप' था, और "ग्रुपिंग सेस" की वजह से आपकी याद आती है। ऐसा लगता है कि कोई भी जवाब सही चिंताओं को संबोधित नहीं कर रहा था, इसलिए मैंने जवाब दिया (और फिर जवाब को सरल बनाने की कोशिश की जिसके परिणामस्वरूप आप जिन समस्याओं को नोट करते हैं)। मैंने आपके उत्तर को उचित रूप से उखाड़ फेंक दिया है, क्योंकि यह उचित दृष्टिकोण है। –

0

यह मेरे लिए काम किया। लेकिन, फिर भी यह साल के लिए दोनों एम और एफ के लिए 0 प्रदर्शित नहीं कर सके जहां कोई डेटा नहीं है:

Select * from 
(
SELECT isnull (SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END),0) as Male, 
     isnull(SUM(CASE WHEN gender = 'F' THEN 1 ELSE 0 END),0) as Female, 
     registeredYear as 'year' 

FROM student 
WHERE registeredDate.Year = 2013 //could be a variable 
group by registeredYear 
) as s 

UNPIVOT 
( 
value FOR gender IN (Male, Female) 
) Sub 
3

आप उपयोग करना चाहिए:

select name, COUNT(*)as tot, 
    COUNT(case when details.gender='male' then 1 end) as male, 
    COUNT(case when details.gender='female' then 1 end) as female 
    from details group by name 
+0

यह ठीक काम करता है .... –

0
select sp.CLASS_Name , count(*) as total 
    , sum(case when si.STDNT_GENDER = 1 then 1 else 0 end) as Male 
    , sum(case when si.STDNT_GENDER = 0 then 1 else 0 end) as Female 
    from SCHOOL_PLANE sp inner join STUDENT_INFO si 
on sp.CLASS_ID=si.STDNT_CLASS_PLANE_ID group by sp.CLASS_Name 

------- 
select sp.CLASS_Name , count(*) as total 
    , sum(case si.STDNT_GENDER when 1 then 1 else 0 end) as Male 
    , sum(case si.STDNT_GENDER when 0 then 1 else 0 end) as Female 
    from SCHOOL_PLANE sp inner join STUDENT_INFO si 
on sp.CLASS_ID=si.STDNT_CLASS_PLANE_ID group by sp.CLASS_Name 
------------ 
select sp.CLASS_Name , count(*) as total 
    , count(case when si.STDNT_GENDER = 1 then 1 end) as Male 
    , count(case when si.STDNT_GENDER = 0 then 1 end) as Female 
    from SCHOOL_PLANE sp inner join STUDENT_INFO si 
on sp.CLASS_ID=si.STDNT_CLASS_PLANE_ID group by sp.CLASS_Name 
+1

आप अपने समाधान पर एक संक्षिप्त विवरण जोड़कर अपना जवाब सुधार सकते हैं। – dakab

संबंधित मुद्दे