4. Queries
4.1. SELECT
语法:
<select-stmt> ::= SELECT ( JSON )? <select-clause>
FROM <tablename>
( WHERE <where-clause> )?
( ORDER BY <order-by> )?
( LIMIT <integer> )?
( ALLOW FILTERING )?
<select-clause> ::= DISTINCT? <selection-list>
| COUNT '(' ( '*' | '1' ) ')' (AS <identifier>)?
<selection-list>
::= <selector> (AS <identifier>)? ( ',' <selector>
(AS <identifier>)? )* | '*'
<selector> ::= <identifier>
| WRITETIME '(' <identifier> ')'
| TTL '(' <identifier> ')'
| <function> '(' (<selector> (',' <selector>)*)? ')'
<where-clause> ::= <relation> ( AND <relation> )*
<relation> ::= <identifier> <op> <term>
| '(' <identifier> (',' <identifier>)* ')' <op> <term-tuple>
| <identifier> IN '(' ( <term> ( ',' <term>)* )? ')'
| '(' <identifier> (',' <identifier>)* ')' IN '(' (
<term-tuple> ( ',' <term-tuple>)* )? ')'
| TOKEN '(' <identifier> ( ',' <identifer>)* ')' <op> <term>
<op> ::= '=' | '<' | '>' | '<=' | '>=' | CONTAINS | CONTAINS KEY
<order-by> ::= <ordering> ( ',' <odering> )*
<ordering> ::= <identifer> ( ASC | DESC )?
<term-tuple> ::= '(' <term> (',' <term>)* ')'
样例:
SELECT name, occupation FROM users WHERE userid IN (199, 200, 207);
SELECT JSON name, occupation FROM users WHERE userid = 199;
SELECT name AS user_name, occupation AS user_occupation FROM users;
SELECT time, value
FROM events
WHERE event_type = 'myEvent'
AND time > '2011-02-03'
AND time <= '2012-01-01'
SELECT COUNT(*) FROM users;
SELECT COUNT(*) AS user_count FROM users;
SELECT语句从rows中读取columns。返回rows的结果集,每个row都包含columns集合。如果使用JSON关键字,则结果返回一个叫”json”的column。更多详情请查看SELECT JSON。
4.1.1. <select-clause>
<select-clause>决定了那些columns需要被查询并返回在结果集中。
<selector>既可以是查询的列名也可以是<function>。函数与<term>一样。WRITETIME函数允许查询出column插入时的timestamp. TTL可以查询出存活时间,如果没有设置过期时间,则返回null
任何<selector>都可以使用AS来启用别名。注意<where-clause>和<order-by>从句应该引用原始的columns名称而非别名。
4.1.2. <where-clause>
<where-clause>指定了哪些rows需要被查询。它由PRIMARY KEY一部分和定义的二级索引的相关的columns组成。
不是所有的关系都是可以查询的。例如,不等关系(其中IN只支持相等关系)在partition key是不支持的(除了在partition key使用token方法才支持不等查询)。而且,对于对于给定的partition key,clustering columns必须是连续的。例如:
CREATE TABLE posts (
userid text,
blog_title text,
posted_at timestamp,
entry_title text,
content text,
category int,
PRIMARY KEY (userid, blog_title, posted_at)
)
下面的查询是允许的:
SELECT entry_title, content FROM posts WHERE userid='john doe' AND blog_title='John''s Blog' AND posted_at >= '2012-01-01' AND posted_at < '2012-01-31'
但是下面的查询是非法的
// Needs a blog_title to be set to select ranges of posted_at
SELECT entry_title, content FROM posts WHERE userid='john doe' AND posted_at >= '2012-01-01' AND posted_at < '2012-01-31'
可以在PRIMARY KEY上使用token函数。
SELECT * FROM posts WHERE token(userid) > token('tom') AND token(userid) < token('bob')
此外,IN只支持partition key的最后一个column和primary key最后一个column。
也可以使用tuple符号将CLUSTERING COLUMNS组合在一起,例如:
SELECT * FROM posts WHERE userid='john doe' AND (blog_title, posted_at) > ('John''s Blog', '2012-01-01')
tuple符号也可以在CLUSTERING COLUMNS使用IN从句:
SELECT * FROM posts WHERE userid='john doe' AND (blog_title, posted_at) IN (('John''s Blog', '2012-01-01), ('Extreme Chess', '2014-06-01'))
CONTAINS操作可以在使用在集合列上(lists,sets,maps)。maps情况,CONTAINS适用于map values。CONTAINS KEY操作可以使用在map columns上且适用于map keys。
4.1.3. <order-by>
ORDER BY选项允许对查询的返回结果进行排序。它以列名为参数(ASE表示升序,DESC表示降序,默认为ASE)。目前排序是受限的(依赖于table的CLUSTERING ORDER)。
LIMIT选项限制SELECT语句查询的返回rows数量。
4.1.5. ALLOW FILTERING
默认情况下,CQL只允许不涉及“filtering”服务器端的select查询, ,即查询所有的(存活)记录将返回结果集(可能部分)。原因是那些“no filtering”查询可预测的性能在某种意义上,它们执行的时间由查询返回的数据量成正比(这可以通过LIMIT控制)。
ALLOW FILTERING选项允许显式地执行需要过滤的查询。请注意查询使用ALLOW FILTERING在性能上不可预知 (上面的定义),即甚至一个查询,选择少量的记录性能取决于的存储在集群中数据总量。
例如,下面的表持有用户信息,birth (有二级索引)和country
CREATE TABLE users (
username text PRIMARY KEY,
firstname text,
lastname text,
birth_year int,
country text
)
CREATE INDEX ON users(birth_year);
以下查询是合法的:
SELECT * FROM users;
SELECT firstname, lastname FROM users WHERE birth_year = 1981;
在这两种情况下,Cassandra保证这些查询性能与返回的数据量成正比。(由于二级索引实现考虑,这个查询可能仍然依赖于集群中节点的数量,间接地取决于存储的数据量。然而,多个节点的数量的大小总是低于用户信息存储的数量)。当然,这两个查询可能返回很大的结果集在实践中,但返回的数据量总是可以通过添加一个LIMIT控制。
然而,下面的查询将被拒绝
SELECT firstname, lastname FROM users WHERE birth_year = 1981 AND country = 'FR';
因为Cassandra不能保证它不需要扫描大量的数据,即使这些查询结果很小。然而,如果你知道你在做什么,你可以通过使用ALLOW FILTERING强制执行该查询,所以下面的查询是有效的:
SELECT firstname, lastname FROM users WHERE birth_year = 1981 AND country = 'FR' ALLOW FILTERING;
5. 数据类型
<type> ::= <native-type>
| <collection-type>
| <tuple-type>
| <string> // Used for custom types. The fully-qualified name of a JAVA class
<native-type> ::= ascii
| bigint
| blob
| boolean
| counter
| date
| decimal
| double
| float
| inet
| int
| text
| time
| timestamp
| timeuuid
| uuid
| varchar
| varint
<collection-type> ::= list '<' <native-type> '>'
| set '<' <native-type> '>'
| map '<' <native-type> ',' <native-type> '>'
<tuple-type> ::= tuple '<' <type> (',' <type>)* '>'
CQL支持一组丰富的数据类型,其中包括集合类型。用户还可以提供自定义类型(通过Cassandra加载继承于AbstractType一个JAVA类)。类型的语法是:
注意,原始类型是关键字,大小写敏感。但它们不是保留字。
下表提供了原始数据类型信息,和每种类型的常量的支持:
type | constants supported | description |
ascii | strings |
|
bigint | integers |
|
blob | blobs | Arbitrary bytes (no validation) |
boolean | booleans | true or false |
counter | integers | Counter column (64-bit signed value). See Counters for details |
date | integers, strings | A date (with no corresponding time value). See Working with dates below for more information. |
decimal | integers, floats |
| Variable-precision decimal |
|
double |
|
| 64-bit IEEE-754 floating point |
|
float | integers, floats |
| 32-bit IEEE-754 floating point |
|
inet | strings |
| An IP address. It can be either 4 bytes long (IPv4) or 16 bytes long (IPv6). There is no inet constant, IP address should be inputed as strings |
|
int | integers |
|
text | strings |
|
time |
|
| A time with nanosecond precision. See Working with time below for more information. |
|
timestamp |
|
| A timestamp. Strings constant are allow to input timestamps as dates, see Working with timestamps below for more information. |
|
timeuuid | uuids |
| Type 1 UUID. This is generally used as a “conflict-free” timestamp. Also see the functions on Timeuuid |
|
uuid | uuids |
|
varchar | strings |
|
varint | integers |
| Arbitrary-precision integer |
|
更多集合类型的使用信息,请查看Working withcollections
5.1. Working with timestamps
timestamp可以是64位整型,表示从格林尼治时间1970年1月1日00:00:00到现在的毫秒数。
string类型格式为:
5.2. Working with dates
date可以是32位无符号整型,表示从格林尼治时间1970年1月1日到现在的天数。
string类型格式为:
2014-01-01
Working with time
time可以是64位整型,表示从midnight到现在的纳秒。
string类型格式为:
08:12:54
08:12:54.123
08:12:54.123456
08:12:54.123456789
5.4. Counters
counter类型用来定义counter columns,一个counter columns为64位整型,其上只能做2种操作:增加或减少(查看UPDATE语法)。注意,此counter的值不能被set。
5.5. Working with collections
集合意味着可以存储非规范化的少量数据。比如”用户的电话号码”,“用户邮箱”等。但是当存储项增长×××时(“用户发送的所有消息”…),那么集合将不再适用,应指定一个table(带有clustering columns)来使用。具体来说,集合有以下限制:
map类型是key-value的键值对集合。
CREATE TABLE users (
id text PRIMARY KEY,
given text,
surname text,
favs map<text, text> // A map of text keys, and text values
)
写入map数据使用JSON-inspired语法完成。
// Inserting (or Updating)
INSERT INTO users (id, given, surname, favs)
VALUES ('jsmith', 'John', 'Smith', { 'fruit' : 'apple', 'band' : 'Beatles' })
添加或修改key-value
// Updating (or inserting)
UPDATE users SET favs['author'] = 'Ed Poe' WHERE id = 'jsmith'
UPDATE users SET favs = favs + { 'movie' : 'Cassablanca' } WHERE id = 'jsmith'
修改或插入可以使用TTL
// Updating (or inserting)
UPDATE users USING TTL 10 SET favs['color'] = 'green' WHERE id = 'jsmith'
TTL将只作用于{ 'color' : 'green' },map的其他项不会影响
删除map记录:
DELETE favs['author'] FROM users WHERE id = 'jsmith'
5.5.2. Sets
set类型集合的值是唯一的
CREATE TABLE p_w_picpaths (
name text PRIMARY KEY,
owner text,
date timestamp,
tags set<text>
);
写入set通过逗号分割。注意,INSERT将会替换整个set
INSERT INTO p_w_picpaths (name, owner, date, tags)
VALUES ('cat.jpg', 'jsmith', 'now', { 'kitten', 'cat', 'pet' });
通过UPDATE来完成添加和删除操作。
UPDATE p_w_picpaths SET tags = tags + { 'cute', 'cuddly' } WHERE name = 'cat.jpg';
UPDATE p_w_picpaths SET tags = tags - { 'lame' } WHERE name = 'cat.jpg';
5.5.3. Lists
list类型集合值可以重复
CREATE TABLE plays (
id text PRIMARY KEY,
game text,
players int,
scores list<int>
)
注意,lists有一些限制和性能损耗,建议尽可能使用set代替list
写入list数据使用JSON-style语法。使用INSERT写入真个list。注意,INSERT将会替换整个list
INSERT INTO plays (id, game, players, scores)
VALUES ('123-afde', 'quake', 3, [17, 4, 2]);
添加(appending 或 prepending)值到list,使用JSON-style数组完成
UPDATE plays SET players = 5, scores = scores + [ 14, 21 ] WHERE id = '123-afde';
UPDATE plays SET players = 5, scores = [ 12 ] + scores WHERE id = '123-afde';
Lists也提供以下操作:通过下标设置,通过下标删除值和通过下标范围删除所有值。但这些操作会产生read-before-update且性能较低。这些操作语法:
UPDATE plays SET scores[1] = 7 WHERE id = '123-afde'; // sets the 2nd element of scores to 7 (raises an error is scores has less than 2 elements)
DELETE scores[1] FROM plays WHERE id = '123-afde'; // deletes the 2nd element of scores (raises an error is scores has less than 2 elements)
UPDATE plays SET scores = scores - [ 12, 21 ] WHERE id = '123-afde'; // removes all occurrences of 12 and 21 from scores
6. Aggregates
6.1. Count
Count函数返回查询的数量
SELECT COUNT(*) FROM plays;
SELECT COUNT(1) FROM plays;
也可以查询列的非空值的数量
SELECT COUNT(scores) FROM plays;
6.2. Max and Min
SELECT MIN(players), MAX(players) FROM plays WHERE game = 'quake';
6.3. Sum
SELECT SUM(players) FROM plays;
6.4. Avg
SELECT AVG(players) FROM plays;