Laravel eloquent where 和 orWhere 获取正确数据的问题
Laravel eloquent where and orWhere issue fetching correct data
我有以下生成此查询的查询构建器:
我的问题在于使用最低和最高价格过滤时销售和股票期权的 where 条件。我的 URL 看起来像这样:
category/men-clothes?sale=no_sale&min_price=10&max_price=10000&per_page=8
sale=no_sale,表示查询执行 where 'sale_price', '=', 0,因此在我的 SQL 查询中是这样的:
and `sale_price` = ? order by `id` desc
然而,它仍然获取sale_price大于0的产品,但是当我切换到on_sale时,只获取sale_price大于0的产品。所以问题只出现在选择没有活跃销售的产品时。
on_stock 和 no_stock 也是如此,它只是无法获取正确的产品。我知道构建器很大,但我无法弄清楚为什么它不能正常工作。它只有在我完全删除 min_price 和 max_price 过滤后才能正常工作,所以它必须位于导致这些问题的价格过滤的 where 和 orWhere 中的某个地方。
.
select * from `products` where exists (select * from `categories` inner join `product_categories` on `categories`.`id` = `product_categories`.`category_id` where `products`.`id` = `product_categories`.`product_id` and `id` = ?) and (`has_variants` = ? and `price` >= ?) or (`has_variants` = ? and `min_price` != ? and `min_price` >= ?) and (`has_variants` = ? and `price` <= ?) or (`has_variants` = ? and `max_price` != ? and `max_price` <= ?) and `sale_price` = ? order by `id` desc
.
$products = Product::whereHas('categories', function ($query) use ($category) {
$query->where('id', '=', $category->id);
})->when(count($brand_list) > 0, function ($query) use ($brand_list) {
$query->whereHas('brand', function ($query) use ($brand_list) {
$query->whereIn('slug', $brand_list);
});
})->when($minPrice, function ($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '>=', $data['active_filters']['min_price']],
])
->orWhere([
['has_variants', '=', 1],
['min_price', '!=', 0],
['min_price', '>=', $data['active_filters']['min_price']],
]);
})->when($maxPrice, function ($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '<=', $data['active_filters']['max_price']],
])
->orWhere([
['has_variants', '=', 1],
['max_price', '!=', 0],
['max_price', '<=', $data['active_filters']['max_price']],
]);
})->when($orderPrice, function ($query) use ($orderPrice) {
$query->orderBy('price', $orderPrice);
})->when(!$orderPrice, function ($query) {
$query->orderBy('id', 'desc');
})->when($stockOrder, function ($query) use ($stockOrder) {
if($stockOrder == 'in_stock') {
$query->where('quantity', '>', 0);
} else if($stockOrder == 'no_stock') {
$query->where('quantity', '=', 0);
}
})->when($saleOrder, function ($query) use ($saleOrder) {
if($saleOrder == 'on_sale') {
$now = time();
$query->where([
['sale_price', '>', 0],
['sale_start', '<', $now],
['sale_end', '>', $now],
])->orWhere([
['sale_price', '>', 0],
['sale_start', '=', 0],
['sale_end', '=', 0],
]);
} else if($saleOrder == 'no_sale') {
$query->where('sale_price', '=', 0);
}
})->when($featuredOrder, function ($query) use ($featuredOrder) {
if($featuredOrder == 'featured') {
$query->where('featured', '=', 1);
} else if($featuredOrder == 'not_featured') {
$query->where('featured', '=', 0);
}
})->when(count($activeColors) > 0, function ($query) use ($activeColors) {
$query->whereHas('colors', function ($query) use ($activeColors) {
$query->whereIn('value', $activeColors);
});
})->when(count($activeSizes) > 0, function ($query) use ($activeSizes) {
$query->whereHas('sizes', function ($query) use ($activeSizes) {
$query->whereIn('value', $activeSizes);
});
})->with(['colors', 'sizes', 'reviewsCount'])->get();
我认为这里的问题是orWhere
。当你使用 orWhere 时,你应该总是用额外的闭包来包裹构造。让我们看看:
->when($minPrice, function ($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '>=', $data['active_filters']['min_price']],
])
->orWhere([
['has_variants', '=', 1],
['min_price', '!=', 0],
['min_price', '>=', $data['active_filters']['min_price']],
]);
})
这部分应该是这样的:
->when($minPrice, function ($query) use ($data) {
$query->where(function($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '>=', $data['active_filters']['min_price']],
])
->orWhere([
['has_variants', '=', 1],
['min_price', '!=', 0],
['min_price', '>=', $data['active_filters']['min_price']],
]);
});
})
正如您在上面看到的那样,整个 where .. orWhere
被包裹在额外的闭包中。
原因很明显。如果你没有额外的关闭,你可以像这样生成查询
WHERE A and B or C and D or E
通常应该是这样的:
WHERE A and (B or C) and (D or E)
因此,当您使用闭包时,它们会向查询添加额外的括号以使其正常工作。
您显然应该以同样的方式包装所有其他 where ... orWhere
结构,以使其按预期工作
我有以下生成此查询的查询构建器:
我的问题在于使用最低和最高价格过滤时销售和股票期权的 where 条件。我的 URL 看起来像这样:
category/men-clothes?sale=no_sale&min_price=10&max_price=10000&per_page=8
sale=no_sale,表示查询执行 where 'sale_price', '=', 0,因此在我的 SQL 查询中是这样的:
and `sale_price` = ? order by `id` desc
然而,它仍然获取sale_price大于0的产品,但是当我切换到on_sale时,只获取sale_price大于0的产品。所以问题只出现在选择没有活跃销售的产品时。 on_stock 和 no_stock 也是如此,它只是无法获取正确的产品。我知道构建器很大,但我无法弄清楚为什么它不能正常工作。它只有在我完全删除 min_price 和 max_price 过滤后才能正常工作,所以它必须位于导致这些问题的价格过滤的 where 和 orWhere 中的某个地方。
.
select * from `products` where exists (select * from `categories` inner join `product_categories` on `categories`.`id` = `product_categories`.`category_id` where `products`.`id` = `product_categories`.`product_id` and `id` = ?) and (`has_variants` = ? and `price` >= ?) or (`has_variants` = ? and `min_price` != ? and `min_price` >= ?) and (`has_variants` = ? and `price` <= ?) or (`has_variants` = ? and `max_price` != ? and `max_price` <= ?) and `sale_price` = ? order by `id` desc
.
$products = Product::whereHas('categories', function ($query) use ($category) {
$query->where('id', '=', $category->id);
})->when(count($brand_list) > 0, function ($query) use ($brand_list) {
$query->whereHas('brand', function ($query) use ($brand_list) {
$query->whereIn('slug', $brand_list);
});
})->when($minPrice, function ($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '>=', $data['active_filters']['min_price']],
])
->orWhere([
['has_variants', '=', 1],
['min_price', '!=', 0],
['min_price', '>=', $data['active_filters']['min_price']],
]);
})->when($maxPrice, function ($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '<=', $data['active_filters']['max_price']],
])
->orWhere([
['has_variants', '=', 1],
['max_price', '!=', 0],
['max_price', '<=', $data['active_filters']['max_price']],
]);
})->when($orderPrice, function ($query) use ($orderPrice) {
$query->orderBy('price', $orderPrice);
})->when(!$orderPrice, function ($query) {
$query->orderBy('id', 'desc');
})->when($stockOrder, function ($query) use ($stockOrder) {
if($stockOrder == 'in_stock') {
$query->where('quantity', '>', 0);
} else if($stockOrder == 'no_stock') {
$query->where('quantity', '=', 0);
}
})->when($saleOrder, function ($query) use ($saleOrder) {
if($saleOrder == 'on_sale') {
$now = time();
$query->where([
['sale_price', '>', 0],
['sale_start', '<', $now],
['sale_end', '>', $now],
])->orWhere([
['sale_price', '>', 0],
['sale_start', '=', 0],
['sale_end', '=', 0],
]);
} else if($saleOrder == 'no_sale') {
$query->where('sale_price', '=', 0);
}
})->when($featuredOrder, function ($query) use ($featuredOrder) {
if($featuredOrder == 'featured') {
$query->where('featured', '=', 1);
} else if($featuredOrder == 'not_featured') {
$query->where('featured', '=', 0);
}
})->when(count($activeColors) > 0, function ($query) use ($activeColors) {
$query->whereHas('colors', function ($query) use ($activeColors) {
$query->whereIn('value', $activeColors);
});
})->when(count($activeSizes) > 0, function ($query) use ($activeSizes) {
$query->whereHas('sizes', function ($query) use ($activeSizes) {
$query->whereIn('value', $activeSizes);
});
})->with(['colors', 'sizes', 'reviewsCount'])->get();
我认为这里的问题是orWhere
。当你使用 orWhere 时,你应该总是用额外的闭包来包裹构造。让我们看看:
->when($minPrice, function ($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '>=', $data['active_filters']['min_price']],
])
->orWhere([
['has_variants', '=', 1],
['min_price', '!=', 0],
['min_price', '>=', $data['active_filters']['min_price']],
]);
})
这部分应该是这样的:
->when($minPrice, function ($query) use ($data) {
$query->where(function($query) use ($data) {
$query->where([
['has_variants', '=', 0],
['price', '>=', $data['active_filters']['min_price']],
])
->orWhere([
['has_variants', '=', 1],
['min_price', '!=', 0],
['min_price', '>=', $data['active_filters']['min_price']],
]);
});
})
正如您在上面看到的那样,整个 where .. orWhere
被包裹在额外的闭包中。
原因很明显。如果你没有额外的关闭,你可以像这样生成查询
WHERE A and B or C and D or E
通常应该是这样的:
WHERE A and (B or C) and (D or E)
因此,当您使用闭包时,它们会向查询添加额外的括号以使其正常工作。
您显然应该以同样的方式包装所有其他 where ... orWhere
结构,以使其按预期工作