Elixir Ecto: 范围数据类型
從 PostgreSQL 9.2 以來(lái), 可以用特定的操作符和函數(shù)存儲(chǔ)和查詢一個(gè)值的范圍. 這是一個(gè)非常不錯(cuò)的特性, 比如在電子商務(wù)應(yīng)用程序方面, 可以用一個(gè)字段 price_range 來(lái)替代 min_price, max_price 表示一個(gè)價(jià)格范圍.
在Ecto中使用范圍數(shù)據(jù)類型
價(jià)格范圍的表示方法如下
[0, 45.67] [30.04, 98.50] [100, 500]我們可以用范圍操作符來(lái)查詢一個(gè)值的范圍
2.5 <@ numrange(1.50,7)Postgresql 支持如下范圍類型
int4range?整數(shù)方位
int8range?—?大整數(shù)范圍
numrange?—?十進(jìn)制數(shù)字范圍(浮點(diǎn))
tsrange?—?不帶時(shí)區(qū)的時(shí)間戳范圍
tstzrange?—?帶時(shí)區(qū)的時(shí)間戳范圍
daterange?—?日期范圍
Ecto 本身為了兼容各個(gè)數(shù)據(jù)庫(kù), 并沒(méi)有支持Postgresql 特有的Range數(shù)據(jù)類型, 但Ecto為我們提供了一個(gè)自定義數(shù)據(jù)類型的方法. 下面我們創(chuàng)建一個(gè) NumRange 類型, 底層用了Postgrex適配器的%Postgrex.Range{}結(jié)構(gòu)
defmodule App.NumRange do @behaviour Ecto.Typedef type, do: :numrangedef cast([lower, upper]) do{:ok, [lower, upper]}enddef cast(_), do: :errordef load(%Postgrex.Range{lower: lower, upper: nil}) do{lower, _} = lower |> to_float{:ok, [lower, nil]}enddef load(%Postgrex.Range{lower: lower, upper: upper}) do{lower, _} = lower |> to_float{upper, _} = upper |> to_float{:ok, [lower, upper]}enddef dump([lower, upper]) do{:ok, %Postgrex.Range{lower: lower, upper: upper, upper_inclusive: false}}enddef dump(_), do: :errordefp to_float(value) dovalue |> Decimal.to_string |> Float.parseend end在模型和遷移腳本中中使用這個(gè)自定義數(shù)據(jù)類型
模型
defmodule App.Product do use App.Web, :modelschema "products" dofield :price_range, App.NumRangetimestampsend end遷移腳本
defmodule App.Repo.Migrations.Product do use Ecto.Migrationdef change docreate table(:products) doadd :price_range, :numrangetimestampsendend end范圍查詢
defmodule App.ProductQuery do import Ecto.Queryalias App.{Repo, Product}def within_price_range(price) doquery =from p in Product,where: fragment("?::numeric <@ ?", ^price, p.price_range)query |> Repo.allend end關(guān)于方位邊界的問(wèn)題, 和數(shù)學(xué)中的范圍符號(hào)是一樣的:
[ 包括下邊界
( 不包括下邊界
] 包括上邊界
) 不包括上邊界
例子
# 創(chuàng)建表 create table products(id int, price_range numrange); # 插入數(shù)據(jù) INSERT INTO products VALUES(1, '[10.0, 100.0]') INSERT INTO products VALUES(1, '[200.0, 300.0]') INSERT INTO products VALUES(1, '[400.0, 500.0]') INSERT INTO products VALUES(1, '[600.0, 700.0]') # 查詢 SELECT * FROM products; +------+--------------------------------------------------------+ | id | price_range | |------+--------------------------------------------------------| | 1 | NumericRange(Decimal('10.0'), Decimal('100.0'), '[]') | | 1 | NumericRange(Decimal('200.0'), Decimal('300.0'), '[]') | | 1 | NumericRange(Decimal('400.0'), Decimal('500.0'), '[]') | | 1 | NumericRange(Decimal('600.0'), Decimal('700.0'), '[]') | +------+--------------------------------------------------------+ # 過(guò)濾 SELECT * FROM products WHERE price_range::numrange @> 99.0 +------+-------------------------------------------------------+ | id | price_range | |------+-------------------------------------------------------| | 1 | NumericRange(Decimal('10.0'), Decimal('100.0'), '[]') | +------+-------------------------------------------------------+參考資料
關(guān)于 Postgresql 的范圍數(shù)據(jù)類型, 參考 范圍類型
Postgresql 范圍操作符
總結(jié)
以上是生活随笔為你收集整理的Elixir Ecto: 范围数据类型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vim文本编辑器
- 下一篇: 2596 售货员的难题