プロが教える店舗&オフィスのセキュリティ対策術

こんばんは。
軽いSQL文がかけずに困っております。
どなたかご教示願います。Postgres8.3になります。

テーブル名 num
カラムはuserとidとします。

データは最下部にあるように持ちます。
a~eのユーザのうち、idが2200番台のうち、2201と2202だけをもつユーザを抽出するSQL文を望みます。

a:2200と2203が存在するので偽
b:真
c:2202が無いので偽
d:2203が存在するので偽
e:真

このようなSQLを書きました。
1.numより2201を持つuser
2.numより2202を持つuser
3.numより22~で始まる以外のuser

それぞれの等しいuserが真と思ったのですが、本来3.では22~始まるidを持たないuser としなければなりませんでした。
ここで詰まってしまい、タイムアップとなってしまいました。
どのようなSQLが望ましいでしょうか。
よろしくお願いいたします。


select * from
num as m,
(select x.user from
(select user from num where id = 2201 group by user_id) as x,
(select user from num where id = 2202 group by user_id) as y,
(select user from num where id::text not like '22%' group by user) as z
where
x.id = y.id and
x.id = z.id and
y.id = z.id) as n
where
m.id = n.id;

num
user,id
a,1000
a,1100
a,2000
a,2100
a,2200
a,2201
a,2202
a,2203
a,3000
b,1000
b,2100
b,2201
b,2202
b,3000
b,3100
c,1000
c,2201
c,2203
c,3000
c,3100
c,3200
d,1000
d,2100
d,2201
d,2202
d,2203
d,3000
d,3100
d,3200
e,1000
e,2201
e,2202
e,3000
e,3100
e,3200
e,3300

A 回答 (4件)

提示されたデータ以外に例えば次のようなデータがあった場合、user=f、gが検索される必要があると言うことでいいですか?



insert into "num" values
('f',1100)
,('f',2100)
,('f',2300)
,('g',2300)
;

(1)
-- idの値が、2200台では2201と2202しか持たないuserを得る
select x."user"
from "num" as x
inner join
(select "user"
from "num"
where "id" between 2200 and 2299
group by "user"
having count("id")=2) as y
on x."user"=y."user" and x."id" in(2201,2202)
group by x."user"
;

(2)
-- idの値が、2200台を持たないuserを得る
(select "user"
from "num"
group by "user"
)
except
(select "user"
from "num"
where "id" between 2200 and 2299
group by "user"
)
;

(3)
-- 二つのクエリをunionで繋ぐ
-- idの値が、2200台では2201と2202しか持たないuserを得る
select x."user"
from "num" as x
inner join
(select "user"
from "num"
where "id" between 2200 and 2299
group by "user"
having count("id")=2) as y
on x."user"=y."user" and x."id" in(2201,2202)
group by x."user"
union
(
-- idの値が、2200台を持たないuserを得る
(select "user"
from "num"
group by "user"
)
except
(select "user"
from "num"
where "id" between 2200 and 2299
group by "user"
)
)
;

(2)のクエリで得た結果を(1)にunionで繋ぐため、()が増えていることに注意してください。
    • good
    • 0
この回答へのお礼

若干説明がたりていませんでしたが2201と2202は必須なためfとgは検索されません。

こちらのSQL参考にさせていただきます。ありがとうございました。

お礼日時:2010/09/09 13:07

すみません。


No2の回答は無視してください
ごめんなさい
    • good
    • 0
この回答へのお礼

いろいろ考えていただきありがとうございます

お礼日時:2010/09/09 12:57

私、勘違いしてましたね(^^ゞ


下記のSQLでどうでしょう?
(Microsoft Accessで確認したためPostgresでは構文が違うかもしれません)

SELECT tableA.user
FROM (
SELECT user
FROM num
WHERE id like '22*'
GROUP BY user
HAVING count(user) = 2
) as tableA,
(
SELECT tableB.user
FROM
(
SELECT user
FROM num
WHERE id like '22*'
GROUP BY user
HAVING count(user) = 2
) as tableB
INNER JOIN num as tableBB
ON tableB.user = tableBB.user
WHERE tableBB.id like '22*'
AND (tableBB.id <> 2201 and tableBB.id <> 2202)
) as tableBBB
WHERE tableA.user <> tableBBB.user
    • good
    • 0

SELECT user


FROM num
WHERE (user='a' OR user='b' OR user='c' OR user='d' OR user='e')
AND (id=2201 OR id=2202)
GROUP BY user

ではダメなんでしょうか?

この回答への補足

この場合、abcde全て抽出されてしまいます。

補足日時:2010/09/07 12:23
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!