2009-01-07 15 views
6

मैं निम्न क्वेरी करने के लिए एक बेहतर तरीका ढूंढ रहा हूं। मैं एक मेज है कि इस तरह दिखता है:एसक्यूएल सहायता: एक नेस्टेड चयन के साथ एकल प्रश्न में पंक्तियों की गणना

game_id | home_team_id | away_team_id 
1  | 100   | 200 
2  | 200   | 300 
3  | 200   | 400 
4  | 300   | 100 
5  | 100   | 400 

और मैं एक प्रश्न निम्नलिखित है कि हर टीम के लिए घर के खेल और दूर खेल की संख्या की गणना और आउटपुट लिखना चाहते हैं: अभी

team_id | home_games | away_games 
100  | 2   | 1 
200  | 2   | 1 
300  | 1   | 1 
400  | 0   | 2 

, मैंने यह राक्षसता लिखा है जो काम करता है, लेकिन यह धीमा है (मुझे पता है कि यह तालिका से पूरी 2,800 पंक्ति खींच रहा है)।

SELECT 
    home_team_id as team_id, 
    (SELECT count(*) FROM `game` WHERE home_team_id = temp_game.home_team_id) as home_games, 
    (SELECT count(*) FROM `game` WHERE home_team_id = temp_game.away_team_id) as away_games 
    FROM (SELECT * FROM `game`) as temp_game 
    GROUP BY home_team_id 

क्या एक एसक्यूएल गुरु मुझे बेहतर तरीके से बाहर निकलने में मदद कर सकता है? मुझे लगता है कि मेरी समस्या यह है कि मुझे समझ में नहीं आता कि गिनती प्रश्नों पर फेंकने के लिए टीम आईडी की एक अलग सूची कैसे प्राप्त करें। मैं शर्त लगाता हूं कि एक बेहतर रखा गया, नेस्टेड चयन के साथ एक बेहतर तरीका है। अग्रिम में धन्यवाद!

+0

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

उत्तर

9

अगर आप team_id और TEAM_NAME के ​​साथ एक और तालिका टीम है यह क्लीनर है।

 
SELECT team_id, team_name, 
    sum(team_id = home_team_id) as home_games, 
    sum(team_id = away_team_id) as away_games 
FROM game, team 
GROUP BY team_id 

क्या हो रहा है: कोई WHERE खंड दो तालिकाओं के बीच कार्टेसियन उत्पाद का कारण बनता है; हम प्रति टीम एक पंक्ति पर वापस जाने के लिए team_id द्वारा समूहबद्ध करते हैं। अब प्रत्येक टीम_आईडी के लिए गेम टेबल से सभी पंक्तियां हैं, इसलिए आपको उन्हें गिनने की आवश्यकता है लेकिन एसक्यूएल गिनती फ़ंक्शन बिल्कुल सही नहीं है (यह सभी पंक्तियों या सभी अलग-अलग पंक्तियों को गिना जाएगा)। तो हम team_id = home_team_id कहते हैं जो 1 या 0 का हल करता है और हम 1 को जोड़ने के लिए योग का उपयोग करते हैं।

TEAM_NAME सिर्फ इसलिए यह कहना कि 'टीम 200 20 घर के खेल था' geeky है है जब हम कहना है कि 'मिट्टी शहर Stranglers 20 घर के खेल था' चाहिए।

पीएस। यह तब भी काम करेगा जब कोई गेम न हो (अक्सर एसक्यूएल में एक समस्या है जहां 0 गेम के साथ एक टीम है और वह पंक्ति दिखाई नहीं देगी क्योंकि शामिल होने में विफल रहता है)।

+0

वाह, मुझे एक गंभीर मस्तिष्क क्रैम्प होना चाहिए क्योंकि यह सही समझ में आता है। मेरे पास वास्तव में एक टीम टेबल है ... लेकिन मैं अपने मस्तिष्क को थोड़ा सा व्यायाम करना चाहता था (और फिर अटक गया और एसओ में आया!)। :) – Greg

+0

मैं आपकी उत्कृष्टता के लिए झुकना! –

+1

वास्तव में एक अच्छा जवाब नहीं है, क्योंकि यह उन कलाकृतियों को मानता है जिन्हें ज्ञात या प्रस्तुत नहीं किया गया था। मैं रोमांचित हूं कि यह मूल पोस्टर के लिए काम करता है, लेकिन यह वास्तव में उपयुक्त नहीं है। यह सिर्फ संयोग है कि यह मूल पोस्टर के लिए काम किया। – casperOne

3

यदि आप टीमों की विशिष्ट सूची चाहते हैं, तो आपको गेम टेबल से दो बार चयन करना होगा, घर और दूर टीमों को मिलाना होगा (सैद्धांतिक रूप से, एक टीम सड़क पर या घर पर अपने सभी गेम खेल सकती है, अगर आपके पास है तर्क यह है कि कि रोकता है, तो आप इस क्वेरी समायोजित कर सकते हैं):

select home_team_id as team_id from game union 
select away_team_id as team_id from game 

union ऑपरेटर सुनिश्चित करें कि आप केवल वापसी सेट में विशिष्ट तत्वों मिलता है (जब तक आप union all का उपयोग करें)

वहां से कर देगा, आप कर सकते हैं अपने डेटा को एकत्रित करने के लिए बाएं बाहरी जुड़ने का उपयोग करें:

select 
    u.team_id, count(h.game_id) as home_games, count(a.game_id) as away_games 
from 
    (
     select home_team_id as team_id from game union 
     select away_team_id as team_id from game 
    ) as u 
     left outer join game as h on h.home_team_id = u.team_id 
     left outer join game as a on a.away_team_id = u.team_id 
group by 
    u.team_id 

यदि आप अपनी तालिका स्कैन को और भी कम करना चाहते हैं (उपर्युक्त चार उत्पादन करेगा), तो आप अधिक कोड जोड़ सकते हैं, लेकिन इससे आपको लागत आएगी। आप team_id साथ पंक्तियों की एक सूची प्राप्त कर सकते हैं, और चाहे या नहीं खेल घर या दूर में खेला गया:

select 
    case ha.home when 0 then g.away_team_id else g.home_team_id end as team_id, 
    case ha.home when 0 then 0 else 1 end as home_games, 
    case ha.home when 0 then 1 else 0 end as away_games 
from 
    game as g, (select 0 as home union select 1 as home) as ha 

वहाँ से, आप बस घर पर खेल हर टीम के लिए योग और दूर कर सकते हैं:

select 
    t.team_id, sum(t.home_games) as home_games, sum(t.away_games) as away_games 
from 
    (
     select 
      case ha.home when 0 then g.away_team_id else g.home_team_id end as team_id, 
      case ha.home when 0 then 0 else 1 end as home_games, 
      case ha.home when 0 then 1 else 0 end as away_games 
     from 
      game as g, (select 0 as home union select 1 as home) as ha 
    ) as t 
group by 
    t.team_id 

इसका परिणाम एक टेबल स्कैन होगा।

2

ग्रेग,

मुझे लगता है कि आपका अंतिम समाधान भाषा-विशिष्ट होगा। लेकिन अगर आप Oracle में यह क्या कर रहे थे, तो आप तालिका केवल एक बार निम्नलिखित के साथ क्वेरी सकता है:

SELECT game.home_team_id AS team_id, 
     SUM(CASE WHEN game.home_team_id = game.away_team_id 
       THEN 1 
       ELSE 0 END) AS home_games, 
     SUM(CASE WHEN game.home_team_id <> game.away_team_id 
       THEN 1 
       ELSE 0 END) AS away_games 
    FROM game 
GROUP BY game.home_team_id 
ORDER BY game.home_team_id; 

आप कहते हैं कि नहीं है एसक्यूएल किस स्वाद आप उपयोग कर रहे तो यह सबसे अच्छा मैं कर सकते हैं।

बेस्ट ऑफ लक,

स्टू

पी.एस. ऐसा लगता है कि मैंने मार्लन रिबुनल के समान समाधान दिया है। मेरे पास एक आसान लिंक नहीं था इसलिए हाथ से कोड बनाना पड़ा।: -/

+0

मैं MySQL 5.0 का उपयोग कर रहा हूं। मैं उम्मीद कर रहा था कि यह विक्रेता-विशिष्ट विवरणों पर झुकाए बिना किया जा सकता है ... लेकिन ओह ठीक है! – Greg

+0

ग्रेग, मैंने इसे विक्रेता-तटस्थ के रूप में लिखने की कोशिश की। मुझे पता है कि केस कई प्रकारों में समर्थित है, इसलिए मैं कहूंगा कि यह कोशिश करें और देखें कि क्या होता है। –

+0

मैंने इसे आज़माया ... यह तेज़ है लेकिन परिणाम थोड़ा दूर थे। मुझे घर के खेल की एक सटीक सूची दिखाई देती है (मुझे पता है कि योग क्या होना चाहिए '), लेकिन वे' दूर खेल 'के लेबल के नीचे हैं। साथ ही, 'होम गेम्स' कॉलम सभी शून्य है, जब मुझे पता है कि इसमें मूल्य होना चाहिए। क्या ट्विक करने के बारे में कोई विचार? – Greg

0

इस प्रयास करें:

Select Z.teamId, 
    Count(H.Game_Id) HomeGames, 
    Count(A.Game_Id) AwayGames 
From (Select Distinct home_team_id TeamId From Game 
     Union 
     Select Distinct away_team_id TeamId From Game) Z 
    Left Join Game H On H.home_team_id = Z.TeamId 
    Left Join Game A On A.away_team_id = Z.TeamId 
Group By Z.TeamId 
+0

संघ खराब नहीं है, लेकिन टीम टेबल का उपयोग करके कम लागत के लिए एक ही समस्या को हल करना चाहिए। –

+0

क्या टीम टेबल? मैंने नहीं देखा कि उसके पास स्कीमा में एक था ... एक टीम टेबल बहुत बेहतर होगा। –

0
declare @ts table 

(
    team_id int 
) 

declare @t table 
(
    id int, 
    h int, 
    a int 
) 

insert into @ts values (100) 
insert into @ts values (200) 
insert into @ts values (300) 
insert into @ts values (400) 

insert into @t values (1, 100, 200) 
insert into @t values (2, 200, 300) 
insert into @t values (3, 200, 400) 
insert into @t values (4, 300, 100) 
insert into @t values (5, 100, 400) 

select s.team_id, t0.home, t1.away 
from @ts s 
    left outer join (select team_id, count(h) as [home] from @ts inner join @t on h = team_id group by team_id) t0 on t0.team_id = s.team_id 
    left outer join (select team_id, count(a) as away from @ts inner join @t on a = team_id group by team_id) t1 on t1.team_id = s.team_id 
0

यहां एक और उदाहरण है।

मैं बाहर बिंदु होगा, हालांकि यह है कि आप टीमों मेज से खंड से अपने शुरू कर देना चाहिए, ताकि आप सभी टीमों को शामिल करने के लिए सुनिश्चित हो जाएगा, भले ही वे अभी तक एक खेल नहीं खेला है।

रूप subselects है, जो बेहतर प्रदर्शन करना चाहिए के बजाय मिलती है इस क्वेरी अपने दो प्रश्नों करता है।

- ध्यान दें: सम्मिलित ifnull मामले में आप mysql का उपयोग कर रहे की तरह है। away_games खंड में अपनी गलती

select 
    teams.team_id 
,case when home.home_game_count is null 
     then 0 
     else home.home_game_count 
    end home_game_count 
,case when away.away_game_count is null 
     then 0 
     else away.away_game_count 
    end as away_game_count 
from 
    ( 
    select home_team_id as team_id from games 
    union 
    select away_team_id as team_id from games 
) teams 
    left outer join 
    ( 
    select home_team_id as team_id, count(*) as home_game_count 
    from games 
    group by home_team_id 
) home 
    on teams.team_id = home.team_id 
    left outer join 
    (
    select away_team_id as team_id, count(*) as away_game_count 
    from games 
    group by away_team_id 
) away 
    on teams.team_id = away.team_id 
0

यह समाधान नहीं बल्कि बदसूरत है, लेकिन यह जल्दी से बड़े डेटासेट भर में काम करना चाहिए। परिणामस्वरूप मूल्य बदलने के बजाय मैंने तुलना ऑपरेटर (<> में) बदल दिया। मुझे समस्या देखने के लिए अतिरिक्त डेटा बनाना पड़ा।

SELECT team_id, 
     teams.team_name, 
     SUM(CASE 
       WHEN game.home_team_id = game.away_team_id THEN 
       1 
       ELSE 
       0 
      END) AS home_games, 
     SUM(CASE 
       WHEN game.home_team_id = game.away_team_id THEN 
       0 
       ELSE 
       1 
      END) AS away_games 
    FROM teams 
    LEFT OUTER JOIN game ON game.home_team_id = teams.team_id 
GROUP BY team_id, teams.team_name 
0

क्षमा करें,:

SELECT 
team_id as team_id, 
coalesce(home_game_counts.games,0) home_games, 
coalesce(away_game_counts.games,0) away_games 
FROM teams 
left join (select home_team_id, count(*) games from games group by home_team_id) as home_game_counts on home_game_counts.home_team_id = teams.team_id 
left join (select away_team_id, count(*) games from games group by away_team_id) as away_game_counts on away_game_counts.away_team_id = teams.team_id 
GROUP BY teams.team_id, home_game_counts.games , 
away_game_counts.games 
संबंधित मुद्दे