webrium / foxql
Foxdb 查询构建器
Requires
- php: ^8
Requires (Dev)
- phpunit/phpunit: ^9
- webrium/core: dev-master
README
属性
- ✔️ 资源使用低
- ✔️ 更轻量更快
- ✔️ 与 Laravel 查询构建器语法相似
- ✔️ 易于配置和使用
Foxdb 查询构建器使用 PDO 参数绑定来保护您的应用程序免受 SQL 注入攻击。无需清理或净化传递给查询构建器的查询绑定的字符串。
通过 composer 安装
composer require webrium\foxdb
-
选择
添加连接配置
use Foxdb\DB; use Foxdb\Config; DB::addConnection('main', [ 'host'=>'localhost', 'port'=>'3306', 'database'=>'test', 'username'=>'root', 'password'=>'1234', 'charset'=>Config::UTF8, 'collation'=>Config::UTF8_GENERAL_CI, 'fetch'=>Config::FETCH_CLASS ]);
'main'
是连接配置的默认名称
从表中检索所有行
您可以使用 DB 门面提供的 table
方法开始一个查询。该方法返回给定表的流畅查询构建器实例,允许您将更多约束附加到查询上,然后最终使用 get
方法检索查询结果。
use Foxdb\DB; $users = DB::table('users')->get(); foreach ($users as $user) { echo $user->name; }
从表中检索单行/列
如果您只需要从数据库表中检索单行,可以使用 DB 门面的 first
方法。此方法将返回一个 stdClass 对象。
$user = DB::table('users')->where('name', 'Jack')->first(); return $user->email;
如果您不需要整个行,可以使用 value
方法从记录中提取单个值。此方法将直接返回列的值。
$email = DB::table('users')->where('name', 'John')->value('email');
要按其 id
列的值检索单行,请使用 find
方法。
$user = DB::table('users')->find(3);
find
方法和 first
方法之间的区别是,如果存在结果,first
方法以 stdClass 的形式返回结果,而 find
方法以 Model 的形式返回结果,这为我们提供了更多功能。(如果值不存在,两种方法都返回 false。)
🆕 从版本 3 及以上,查询可用于查找
$user = User::find(3); if($user){ $user->name = 'Tom'; $user->save(); // update name } $user = User::where('phone', '09999999999')->find(); if($user){ $user->phone = '09999999998'; $user->save(); // update user phone number }
检索列值列表
您可以使用 pluck
方法。在这个例子中,我们将检索用户头衔的集合。
use Foxdb\DB; $titles = DB::table('users')->pluck('title'); foreach ($titles as $title) { echo $title; }
您可以通过向 pluck 方法提供第二个参数来指定结果集合应使用其键的列。
$titles = DB::table('users')->pluck('title', 'name'); foreach ($titles as $name => $title) { echo $title; }
分块结果
如果您需要处理成千上万的数据库记录,请考虑使用 DB 门面提供的 chunk
方法。该方法一次检索一小块结果,并将每个块馈送到闭包进行处理。例如,让我们每次以 100 条记录的块来检索整个用户表。
use Foxdb\DB; DB::table('users')->orderBy('id')->chunk(100, function ($users) { foreach ($users as $user) { // } });
您可以通过从闭包中返回 false 来停止进一步处理更多块。
DB::table('users')->orderBy('id')->chunk(100, function ($users) { // Process the records... return false; });
您可以使用 each
方法。
use Foxdb\DB; DB::table('users')->orderBy('id')->each(function ($user) { // });
分页
FoxDB 为分页创建了一个简单的方法。在下面的示例中,结果数限制为 10 条记录,您可以通过更改页面编号来获取信息。
$page = 1; $list = DB::table('posts') ->is('active') ->paginate(10, $page);
其输出是一个包含以下属性的 stdClass 对象
$list->total; // The total number of rows $list->count; // The number of rows received on the current page $list->per_page; // The number of rows to display on each page $list->prev_page; // Previous page number. If not available, its value is false $list->next_page; // next page number. If not available, its value is false $list->current_page; // Current page number $list->data; // List of data rows
聚合
查询构建器还提供了各种方法来检索聚合值,如 count
(计数)、max
(最大值)、min
(最小值)、avg
(平均值)和 sum
(总和)。您可以在构建查询后调用这些方法中的任何一种。
use Foxdb\DB; $users = DB::table('users')->count(); $price = DB::table('orders')->max('price');
当然,您可以将这些方法与其他子句结合使用,以微调您的聚合值计算方式。
$price = DB::table('orders') ->where('finalized', 1) ->avg('price');
确定是否存在记录
您可以使用 exists 和 doesntExist 方法来确定是否存在符合查询约束的记录,而不是使用 count 方法。
if (DB::table('orders')->where('finalized', 1)->exists()) { // ... } if (DB::table('orders')->where('finalized', 1)->doesntExist()) { // ... }
选择语句
指定选择子句
您并不总是想从数据库表中选择所有列。使用 select
方法,您可以指定查询的定制“选择”子句。
use Foxdb\DB; $users = DB::table('users') ->select('name', 'email as user_email') ->get(); // Or you can send as an array $users = DB::table('users') ->select(['name', 'email as user_email']) ->get();
但有一种更现代的方法。您可以参考以下示例
$users = DB::table('users') ->select(function($query){ $query->field('name'); $query->field('email')->as('user_email'); }) ->get();
原始表达式
有时您可能需要在查询中插入任意字符串。要创建原始字符串表达式,您可以使用由 DB
门面提供的 raw
方法。
$users = DB::table('users') ->select(DB::raw('count(*) as user_count, status')) ->where('status', '<>', 1) ->groupBy('status') ->get();
如下所示使用参数:
DB::raw('count(?)',[
'id'
])
⚠️ 原始语句将被作为字符串注入到查询中,因此您应非常小心,以避免创建 SQL 注入漏洞。
我们的建议
但出于此目的,最好使用以下方法来避免 SQL 注入
攻击。
$users = DB::table('users') ->select(function($query){ $query->count('*')->as('user_count') $query->field('status'); }) ->get();
在这个结构中,您可以使用 field
、count
、sum
、avg
、min
、max
、all
、as
方法。
原始方法
除了使用 DB::raw 方法外,您还可以使用以下方法将原始表达式插入查询的各个部分。请记住,Foxdb 不能保证使用原始表达式的任何查询都受到 SQL 注入漏洞的保护。
whereRaw / orWhereRaw
whereRaw 和 orWhereRaw 方法可用于将原始“where”子句注入到查询中。这些方法接受一个可选的绑定数组作为它们的第二个参数。
$orders = DB::table('orders') ->whereRaw('price > IF(state = "TX", ?, 100)', [200]) ->get();
havingRaw / orHavingRaw
havingRaw 和 orHavingRaw 方法可用于将原始字符串作为“having”子句的值。这些方法接受一个可选的绑定数组作为它们的第二个参数。
$orders = DB::table('orders') ->select('department', DB::raw('SUM(price) as total_sales')) ->groupBy('department') ->havingRaw('SUM(price) > ?', [2500]) ->get();
内连接子句
查询构建器还可以用于向查询中添加连接子句。要执行基本的“内连接”,您可以使用查询构建器实例上的 join 方法。传递给 join 方法的第一个参数是需要连接的表名,而其余参数指定连接的列约束。您甚至可以在单个查询中连接多个表。
use Foxdb\DB; $users = DB::table('users') ->join('contacts', 'users.id', '=', 'contacts.user_id') ->join('orders', 'users.id', '=', 'orders.user_id') ->select('users.*', 'contacts.phone', 'orders.price') ->get();
在 Foxdb 中,您可以更容易地做到这一点。
$users = DB::table('users') ->select('users.*', 'orders.price') ->join('orders.user_id', 'users.id') ->get();
在这个结构中,您输入您想连接的表名及其外键('orders.user_id'
),然后是主键('user.id'
)。
左连接 / 右连接子句
如果您想执行“左连接”或“右连接”而不是“内连接”,请使用 leftJoin 或 rightJoin 方法。这些方法与 join 方法的签名相同。
$users = DB::table('users') ->leftJoin('posts', 'users.id', '=', 'posts.user_id') ->get();
$users = DB::table('users') ->rightJoin('posts', 'users.id', '=', 'posts.user_id') ->get();
交叉连接子句
您可以使用 crossJoin 方法执行“交叉连接”。交叉连接生成第一个表和连接表的笛卡尔积。
$sizes = DB::table('sizes') ->crossJoin('colors') ->get();
WHERE 子句
您可以使用查询构建器的 where 方法向查询中添加“where”子句。where 方法的最基本调用需要三个参数。第一个参数是列名。第二个参数是一个运算符,可以是数据库支持的所有运算符中的任何一个。第三个参数是与列值比较的值。
例如,以下查询检索了 votes 列值为 100 且 age 列值大于 35 的用户。
$users = DB::table('users') ->where('votes', '=', 100) ->where('age', '>', 35) ->get();
为了方便起见,如果您想验证一列是否等于某个给定值,可以将该值作为 where 方法的第二个参数传递。Foxdb 会假设您想使用 = 操作符。
$users = DB::table('users')->where('votes', 100)->get();
如前所述,您可以使用您数据库系统支持的任何操作符。
$users = DB::table('users') ->where('votes', '>=', 100) ->get();
$users = DB::table('users') ->where('votes', '<>', 100) ->get();
$users = DB::table('users') ->where('name', 'like', 'T%') ->get();
或者 Where 子句
在链式调用查询构建器的 where 方法时,"where" 子句将使用 and 操作符连接在一起。但是,您可以使用 orWhere 方法使用 or 操作符将一个子句连接到查询中。orWhere 方法接受与 where 方法相同的参数。
$users = DB::table('users') ->where('votes', '>', 100) ->orWhere('name', 'John') ->get();
如果您需要在括号内分组 "or" 条件,可以将闭包作为 orWhere 方法的第一个参数传递。
$users = DB::table('users') ->where('votes', '>', 100) ->orWhere(function($query) { $query->where('name', 'Abigail') ->where('votes', '>', 50); }) ->get();
上面的例子将产生以下 SQL
select * from users where votes > 100 or (name = 'Abigail' and votes > 50)
Where Not 子句
whereNot
和 orWhereNot
方法可以用来否定一组查询约束。例如,以下查询排除了正在清仓或价格低于十的产品。
$products = DB::table('products') ->whereNot(function ($query) { $query->where('clearance', true) ->orWhere('price', '<', 10); }) ->get();
附加 Where 子句
whereBetween / orWhereBetween
whereBetween
方法验证列的值是否在两个值之间。
$users = DB::table('users') ->whereBetween('votes', [1, 100]) ->get();
whereNotBetween / orWhereNotBetween
whereNotBetween
方法验证列的值是否位于两个值之外。
$users = DB::table('users') ->whereNotBetween('votes', [1, 100]) ->get();
whereIn / whereNotIn / orWhereIn / orWhereNotIn
whereIn
方法验证给定列的值是否包含在给定的数组中。
$users = DB::table('users') ->whereIn('id', [1, 2, 3]) ->get();
whereNotIn
方法验证给定列的值是否不包含在给定的数组中。
$users = DB::table('users') ->whereNotIn('id', [1, 2, 3]) ->get();
whereNull / whereNotNull / orWhereNull / orWhereNotNull
whereNull
方法验证给定列的值是否为 NULL。
$users = DB::table('users') ->whereNull('updated_at') ->get();
whereNotNull
方法验证列的值不是 NULL。
$users = DB::table('users') ->whereNotNull('updated_at') ->get();
whereDate / whereMonth / whereDay / whereYear / whereTime
whereDate
方法可以用作将列的值与日期进行比较。
$users = DB::table('users') ->whereDate('created_at', '2016-12-31') ->get();
whereMonth
方法可以用作将列的值与特定月份进行比较。
$users = DB::table('users') ->whereMonth('created_at', '12') ->get();
whereDay
方法可以用作将列的值与月份中的特定一天进行比较。
$users = DB::table('users') ->whereDay('created_at', '31') ->get();
whereYear
方法可以用作将列的值与特定年份进行比较。
$users = DB::table('users') ->whereYear('created_at', '2016') ->get();
whereTime
方法可以用作将列的值与特定时间进行比较。
$users = DB::table('users') ->whereTime('created_at', '=', '11:20:45') ->get();
whereColumn / orWhereColumn
whereColumn
方法可以用作验证两个列是否相等。
$users = DB::table('users') ->whereColumn('first_name', 'last_name') ->get();
您还可以向 whereColumn
方法传递一个比较操作符。
$users = DB::table('users') ->whereColumn('updated_at', '>', 'created_at') ->get();
排序、分组、限制 & 偏移
排序
orderBy 方法
orderBy
方法允许您按给定列对查询结果进行排序。orderBy
方法的第一个参数应该是您希望排序的列,第二个参数确定排序方向,可以是 asc 或 desc。
$users = DB::table('users') ->orderBy('name', 'desc') ->get();
要按多个列排序,您可以多次调用 orderBy。
$users = DB::table('users') ->orderBy('name', 'desc') ->orderBy('email', 'asc') ->get();
最新 & 最老 方法
latest
和 oldest
方法允许您轻松按日期排序结果。默认情况下,结果将按表的 created_at
列排序。或者,您也可以传递您希望排序的列名。
$user = DB::table('users') ->latest() ->first();
随机排序
inRandomOrder 方法可以用于随机排序查询结果。例如,您可以使用此方法获取一个随机用户。
$randomUser = DB::table('users') ->inRandomOrder() ->first();
分组
groupBy & having 方法
正如您所预期的,groupBy 和 having 方法可以用来对查询结果进行分组。having 方法的签名与 where 方法类似。
$users = DB::table('users') ->groupBy('account_id') ->having('account_id', '>', 100) ->get();
您可以将多个参数传递给groupBy方法以按多个列进行分组
$users = DB::table('users') ->groupBy('first_name', 'status') ->having('account_id', '>', 100) ->get();
要构建更复杂的having语句,请参阅havingRaw方法。
限制和偏移量
skip & take方法
您可以使用skip
和take
方法来限制查询返回的结果数量,或者跳过查询中给定数量的结果
$users = DB::table('users')->skip(10)->take(5)->get();
或者,您可以使用limit
和offset
方法。这些方法的功能与take和skip方法相对应
$users = DB::table('users') ->offset(10) ->limit(5) ->get();
插入语句
查询构建器还提供了一个insert
方法,可以用于将记录插入数据库表。insert方法接受一个列名和值的数组
DB::table('users')->insert([ 'email' => 'kayla@example.com', 'votes' => 0 ]);
自动增加的ID
如果表具有自动增加的ID,请使用insertGetId
方法插入记录并检索ID
$id = DB::table('users')->insertGetId( ['email' => 'john@example.com', 'votes' => 0] );
更新语句
除了将记录插入数据库外,查询构建器还可以使用update方法更新现有记录。update方法类似于insert方法,接受一个表示要更新的列的列名和值对的数组。update方法返回受影响的行数。您可以使用where子句约束更新查询
$affected = DB::table('users') ->where('id', 1) ->update(['votes' => 1]);
递增和递减
查询构建器还提供了方便的方法来增加或减少给定列的值。这两种方法都至少接受一个参数:要修改的列。可以提供一个第二个参数来指定列应增加或减少的量
DB::table('users')->increment('votes'); DB::table('users')->increment('votes', 5); DB::table('users')->decrement('votes'); DB::table('users')->decrement('votes', 5);
删除语句
DB::table('users')->where('id', $id)->delete();
特殊功能
您可以使用更令人愉悦的语法,它不仅缩短了代码,还有助于使代码更易读
方法:is / true / false
要创建基于布尔值的查询,可以使用true
和false
或is
方法
$active_list = DB::table('users')->is('active')->get(); // OR $active_list = DB::table('users')->true('active')->get();
$inactive_list = DB::table('users')->is('active', false)->get(); //OR $inactive_list = DB::table('users')->false('active')->get();
方法:and / or / in
您不需要连续使用where方法进行查询。您可以使用and方法或使用or代替orWhere。
示例
DB::table('users') ->is('active') ->and('credit', '>', 0) ->or('vip', true) ->get();
DB::table('users') ->in('id', [1,5,10]) ->get();
还有其他方法可用,如下所示的方法
not(..)
/ orNot(..)
in(..)
/ notIn(..)
/ orIn(..)
/ orNotIn(..)
like(..)
/ orLike(..)
null(..)
/ orNull(..)
/ notNull(..)
/ orNotNull(..)
date(..)
/ orDate(..)
year(..)
/ orYear(..)
month(..)
/ orMonth(..)
day(..)
/ orDay(..)
time(..)
/ orTime(..)