Laravel CTE(WITH)query builder

fdbelqdn  于 2023-03-31  发布在  其他
关注(0)|答案(3)|浏览(150)

我正在使用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版本

nbewdwxp

nbewdwxp1#

你的查询的问题是,你试图在子查询中引用CTE(T),但你实际上没有在查询中定义CTE。要解决这个问题,你需要在子查询中引用它之前使用with()方法在Laravel查询中定义T CTE。
就像这样

$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();
tkqqtvp1

tkqqtvp12#

使用(未测试)

$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();
zpgglvta

zpgglvta3#

$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();

请注意,在更新的版本中,我:
在$realQuery的select()方法中添加了缺少的Id和ENERGY_Total列
交换了whereBetween()方法中Time值的顺序以匹配SQL查询
删除select()和unionAll()方法中不必要的DB::raw()调用
将array_keys($devicesArr)更改为硬编码数组['esp8266/meter 3 Phase 2','esp8266/meter 3 Phase 3'],该数组与SQL查询匹配
在$a子查询中将DB::raw('')更改为''
在主查询的select()方法中将DB::raw('T. ')更改为'T.'

相关问题