联合所有的 Laravel CTE(WITH)查询构建器

问题描述 投票:0回答:3

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

php mysql laravel union common-table-expression
3个回答
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();


0
投票

使用(未测试)

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

0
投票
$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.'

© www.soinside.com 2019 - 2024. All rights reserved.