我正在使用 Laravel 包
staudenmeir/laravel-cte
但无法表达我想要的查询
我的SQL查询:
WITH T AS (
SELECT Id, DeviceType, DeviceId, ENERGY_Total, `Time`
FROM devices_sensor_data
WHERE `Time` BETWEEN '2023-03-28 00:00:00' AND '2023-03-27 20:40:00'
AND `DeviceId` IN ('esp8266/meter3Phase2' , 'esp8266/meter3Phase3')
)
(SELECT * FROM T ORDER BY Time LIMIT 1)
UNION ALL
(SELECT * FROM T ORDER BY Time DESC LIMIT 1);
我的铰接式 laravel 查询
$realQuery = DB::table('devices_sensor_data')
->select(DB::raw('DeviceId, '.$chartType.', Time'))
->whereIn('DeviceId', array_keys($devicesArr))
->whereBetween('Time', [$from, $to]);
$a = DB::table('T')
->select(DB::raw('*'))
->orderBy('Time')
->limit(1);
$sensor_data = DB::query()
->withExpression('T', $realQuery)
->select(DB::raw('T.*'))
->orderBy('Time', 'DESC')
->limit(1)
->unionAll($a)
->get();
这个查询给我语法错误
我用的是
staudenmeir/laravel-cte : 1.0
版本
您的查询的问题是您试图在子查询中引用 CTE(T),但您实际上并未在查询中定义 CTE。要解决此问题,您需要在 Laravel 中定义 T CTE在子查询中引用它之前使用 with() 方法进行查询。
像这样
$realQuery = DB::table('devices_sensor_data')
->select(DB::raw('Id, DeviceType, DeviceId, ENERGY_Total, Time'))
->whereIn('DeviceId', ['esp8266/meter3Phase2', 'esp8266/meter3Phase3'])
->whereBetween('Time', ['2023-03-28 00:00:00', '2023-03-27 20:40:00']);
$sensor_data = DB::query()
->withExpression('T', $realQuery)
->select(DB::raw('*'))
->from('T')
->orderBy('Time')
->limit(1)
->unionAll(
DB::query()
->select(DB::raw('*'))
->from('T')
->orderBy('Time', 'DESC')
->limit(1)
)
->get();
使用(未测试)
$startTime = '2023-03-28 00:00:00';
$endTime = '2023-03-27 20:40:00';
$deviceIds = ['esp8266/meter3Phase2', 'esp8266/meter3Phase3'];
$query = CteQueryBuilder::withExpression('T', function ($query) use ($startTime, $endTime, $deviceIds) {
$query->select('Id', 'DeviceType', 'DeviceId', 'ENERGY_Total', 'Time')
->from('devices_sensor_data')
->whereIn('DeviceId', $deviceIds)
->whereBetween('Time', [$endTime, $startTime]);
});
$firstResult = $query->from('T')->orderBy('Time')->limit(1);
$secondResult = $query->from('T')->orderByDesc('Time')->limit(1);
$results = $firstResult->unionAll($secondResult)->get();
在文件顶部添加这个
use Staudenmeir\LaravelCte\Query\Builder as CteQueryBuilder;
或以通用方式(未测试)
$query = DB::table('devices_sensor_data')
->select(DB::raw('Id, DeviceType, DeviceId, ENERGY_Total, Time'))
->whereIn('DeviceId', array_keys($devicesArr))
->whereBetween('Time', [$from, $to]);
$firstResult = DB::table('T')
->select(DB::raw('*'))
->orderBy('Time')
->limit(1);
$secondResult = DB::table('T')
->select(DB::raw('*'))
->orderBy('Time', 'desc')
->limit(1);
$results = DB::query()
->withExpression('T', $query)
->fromSub($firstResult, 'first')
->unionAll($secondResult)
->get();
$realQuery = DB::table('devices_sensor_data')
->select('Id', 'DeviceType', 'DeviceId', 'ENERGY_Total', 'Time')
->whereIn('DeviceId', ['esp8266/meter3Phase2', 'esp8266/meter3Phase3'])
->whereBetween('Time', ['2023-03-27 20:40:00', '2023-03-28 00:00:00']);
$a = DB::table('T')
->select('*')
->orderBy('Time')
->limit(1);
$sensor_data = DB::query()
->withExpression('T', $realQuery)
->select('T.*')
->orderBy('Time', 'DESC')
->limit(1)
->unionAll($a)
->get();
请注意,在更新版本中,我:
将缺少的 Id 和 ENERGY_Total 列添加到 $realQuery 中的 select() 方法
交换了 whereBetween() 方法中时间值的顺序以匹配 SQL 查询
删除了 select() 和 unionAll() 方法中不必要的 DB::raw() 调用
将 array_keys($devicesArr) 更改为硬编码数组 ['esp8266/meter3Phase2', 'esp8266/meter3Phase3'],这与 SQL 查询匹配
在 $a 子查询中将 DB::raw('') 更改为 ''
在主查询的 select() 方法中将 DB::raw('T.') 更改为 'T.'