※ 発表には Haskell のコードが出てきますが、見た目の気分を感じとるぐらいで十分です。 対応するSQLも見せるので意味がわかると思います。
結合式を組み立てるとき:
When building joined query:
SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 INNER JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
$$\{ (p, b) | p \in P, b \in B, \pi_{P.name}(p) = \pi_{B.name}(b) \}$$
$$\{ (p, b) | p \in P, b \in B, \pi_{P.name}(p) = \pi_{B.name}(b) \}$$
※ <- と $\in$
[ (p, b)
| p <- person, b <- birthday , P.name p == B.name b ]
-- 内包表記/Comprehension
do { p <- person; b <- birthday; guard (P.name p == B.name b)
; return (p, b) } -- List Monad
どちらの記法でも同じの意味/The same meanings
do { p <- person; b <- birthday; guard (P.name p == B.name b)
; return (p, b) } -- List Monad
結合式をリスト内包表記あるいはList Monad のように組み立てる:
Building a joined query like list comprehension or list monad:
personAndBirthday :: Relation () (Person, Birthday)
personAndBirthday = relation $ do
p <- query person
b <- query birthday -- 結合積の蓄積
-- Join product accumulated
on $ p ! Person.name' .=. b ! Birthday.name'
return $ p >< b
personAndBirthday :: Relation () (Person, Birthday)
personAndBirthday = relation $ do
p <- query person
b <- query birthday -- 結合積の集積
-- Join product accumulated
on $ p ! Person.name' .=. b ! Birthday.name'
return $ p >< b
SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 INNER JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
personAndBirthdayL :: Relation () (Person, Maybe Birthday)
personAndBirthdayL = relation $ do
p <- query person
b <- queryMaybe birthday
on $ just (p ! Person.name') .=. b ?! Birthday.name'
return $ p >< b
SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 LEFT JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
agesOfFamilies :: Relation () (String, Maybe Int32)
agesOfFamilies = aggregateRelation $ do
p <- query person
gFam <- groupBy $ p ! Person.family' -- Specify grouping key
return $ gFam >< sum' (p ! Person.age') -- Aggregated results
SELECT ALL T0.family AS f0, SUM(T0.age) AS f1
FROM EXAMPLE.person T0
GROUP BY T0.family
sameBirthdayHeisei' :: Relation () (Day, Int64)
sameBirthdayHeisei' = aggregateRelation $ do
p <- query person
b <- query birthday
on $ p ! Person.name' .=. b ! Birthday.name'
wheres $
b ! Birthday.day' .>=. value (fromGregorian 1989 1 8)
gbd <- groupBy $ b ! Birthday.day'
having $ count (p ! Person.name') .>. value (1 :: Int64)
return $ gbd >< count (p ! Person.name')
平成生まれで誕生日が同じ人を数える
counts people with the same birthday, who were born in the Heisei period.
SELECT ALL T1.day AS f0, COUNT(T0.name) AS f1
FROM EXAMPLE.person T0 INNER JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
WHERE (T1.day >= DATE '1989-01-08')
GROUP BY T1.day
HAVING (COUNT(T0.name) > 1)
SELECT ALL T1.day AS f0, COUNT(T0.name) AS f1
FROM EXAMPLE.person T0 INNER JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
WHERE (T1.day >= DATE '1989-01-08')
GROUP BY T1.day
HAVING (COUNT(T0.name) > 1)
sameBirthdayHeisei :: Relation () (Day, Int64)
sameBirthdayHeisei = aggregateRelation $ do
p <- query person
b <- query birthday
on $ p ! Person.name' .=. b ! Birthday.name'
let birthDay = b ! Birthday.day'
wheres $ birthDay .>=. value (fromGregorian 1989 1 8)
gbd <- groupBy birthDay
let personCount = count $ p ! Person.name'
having $ personCount .>. value 1
return $ gbd >< personCount
personAndBirthdayO :: Relation () (Person, Birthday)
personAndBirthdayO = relation $ do
p <- query person
b <- query birthday
on $ p ! Person.name' .=. b ! Birthday.name'
orderBy (b ! Birthday.day') Asc -- Specify ordering key
orderBy (p ! Person.name') Asc
return $ p >< b
orders by birthday and then name:
SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 INNER JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
ORDER BY T1.day ASC, T0.name ASC
SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 INNER JOIN EXAMPLE.birthday T1
ON (T0.name = T1.name)
ORDER BY T1.day ASC, T0.name ASC
specifyPerson :: Relation String (Person, Birthday)
specifyPerson = relation' $ do
pb <- query personAndBirthday -- Re-use predefined
(ph, ()) <- placeholder
(\ph' -> wheres $ pb ! fst' ! Person.name' .=. ph')
return (ph, pb)
名前をプレースホルダーで指定する:
specifies a person name using a placeholder:
SELECT ALL T2.f0 AS f0, T2.f1 AS f1, T2.f2 AS f2,
T2.f3 AS f3, T2.f4 AS f4
FROM (SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 INNER JOIN
EXAMPLE.birthday T1
ON (T0.name = T1.name)) T2
WHERE (T2.f0 = ?)
SELECT ALL T2.f0 AS f0, T2.f1 AS f1, T2.f2 AS f2,
T2.f3 AS f3, T2.f4 AS f4
FROM (SELECT ALL T0.name AS f0, T0.age AS f1, T0.family AS f2,
T1.name AS f3, T1.day AS f4
FROM EXAMPLE.person T0 INNER JOIN
EXAMPLE.birthday T1
ON (T0.name = T1.name)) T2
WHERE (T2.f0 = ?)
ウィンドウを組み立てる:
Building windows:
ageRankOfFamilies :: Relation () ((Int64, String), Int32)
ageRankOfFamilies = relation $ do
my <- query myTable
return $
rank `over` do
partitionBy $ my ! family' -- Monad to build window
orderBy (my ! age') Desc
><
my ! family' >< my ! age'
SELECT ALL
RANK() OVER (PARTITION BY T0.family
ORDER BY T0.age DESC) AS f0,
T0.family AS f1, T0.age AS f2
FROM PUBLIC.my_table T0
SELECT ALL
RANK() OVER (PARTITION BY T0.family
ORDER BY T0.age DESC) AS f0,
T0.family AS f1, T0.age AS f2
FROM PUBLIC.my_table T0
静的型付けされた式を組み立てる演算子
Operators which builds statically typed expressions
query :: (MonadQualify ConfigureQuery m, MonadQuery m)
=> Relation () r
-> m (Projection Flat r)
queryMaybe :: (MonadQualify ConfigureQuery m, MonadQuery m)
=> Relation () r
-> m (Projection Flat (Maybe r))
on :: MonadQuery m => Projection Flat (Maybe Bool) -> m ()
静的型付けされた式を組み立てる演算子
Operators which builds statically typed expressions
groupBy :: MonadAggregate m
=> Projection Flat r
-- ^ Projection to add into group by
-> m (Projection Aggregated r)
-- ^ Result context and aggregated projection
count :: Projection Flat a -> Projection Aggregated Int64
max' :: Ord a
=> Projection Flat a -> Projection Aggregated (Maybe a)
静的型付けされた式を組み立てる演算子
Operators which builds statically typed expressions
restrict :: MonadRestrict c m
=> Projection c (Maybe Bool)
-> m ()
wheres :: MonadRestrict Flat m
=> Projection Flat (Maybe Bool)
-> m ()
having :: MonadRestrict Aggregated m
=> Projection Aggregated (Maybe Bool)
-> m ()
静的型付けされた式を組み立てる演算子
Operators which builds statically typed expressions
orderBy :: Monad m
=> Projection c t
-- ^ Ordering terms to add
-> Order
-- ^ Order direction -- Asc | Desc
-> Orderings c m ()
-- ^ Result context with ordering