Проверьте, существует ли результат подзапроса, а затем вычтите его - PullRequest
0 голосов
/ 21 июня 2020

У меня есть большой запрос, в котором мне нужно вычесть значение подзапроса. Я пробовал JOINS, но они не работают, так как есть несколько группировок, которые приводят к неправильным результатам математического уравнения. Запрос:

SELECT 
o.order_id, 
sa.shipping_name AS user, 
ROUND(SUM(op.price * op.amount) + o.shipping_price - IF(EXISTS(SELECT SUM(od.discount) FROM order_discounts od WHERE od.order_id=o.order_id GROUP BY od.order_id), (SELECT SUM(od.discount) FROM order_discounts od WHERE od.order_id=o.order_id GROUP BY od.order_id), 0), 2) 

AS order_total FROM 
( orders o JOIN order_products op ON op.order_id=o.order_id ) 
LEFT OUTER JOIN shipping_addresses sa ON o.shipping_address_id = sa.shipping_address_id 
GROUP BY o.order_id ORDER BY o.order_date DESC, o.user_id DESC

Как видите, мне нужно запустить запрос, чтобы проверить, есть ли скидка, а затем запустить его снова, чтобы вычесть. Итак, у меня вопрос: как я могу получить часть «ВЫБРАТЬ СУММ (od.discount) ...» только один раз?

Структура таблиц:

CREATE TABLE `orders` (
  `order_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `order_date` datetime NOT NULL,
  `shipping_address_id` int(11) NOT NULL,
  `shipping_price` float NOT NULL,
  `shipping_option_id` int(11) NOT NULL,
  `order_currency` varchar(5) CHARACTER SET utf8mb4 NOT NULL,
  `billing_address_id` int(11) NOT NULL,
  `status` enum('unpaid','paid','shipped') CHARACTER SET utf8mb4 NOT NULL,
  `admin_id` int(11) NOT NULL,
  `descr` text CHARACTER SET utf8mb4 NOT NULL,
  `payment_type` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
  `invoice_url` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
  `amount_paid` double NOT NULL,
  `stripe_src_id` varchar(50) NOT NULL,
  `ipn_message` text NOT NULL,
  `stripe_client_secret` varchar(255) NOT NULL,
  `order_total` double NOT NULL,
  `paid_via` enum('paypal','stripe','bancontact') NOT NULL,
  `order_notes` text CHARACTER SET utf8mb4 NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `order_discounts`
--

CREATE TABLE `order_discounts` (
  `order_id` int(11) NOT NULL,
  `discount_id` int(11) NOT NULL,
  `discount` float NOT NULL,
  `currency` varchar(5) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

-- --------------------------------------------------------

--
-- Table structure for table `order_products`
--

CREATE TABLE `order_products` (
  `op_id` int(11) NOT NULL,
  `order_id` int(11) NOT NULL,
  `product_id` int(11) NOT NULL,
  `amount` int(7) NOT NULL,
  `price` double NOT NULL,
  `currency` varchar(5) CHARACTER SET utf8mb4 NOT NULL,
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `shipping_addresses`
--

CREATE TABLE `shipping_addresses` (
  `shipping_address_id` int(11) NOT NULL,
  `shipping_name` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1 Ответ

1 голос
/ 21 июня 2020

Похоже, что на order_id есть несколько строк в order_products и в order_discounts. Если это так, я бы рекомендовал агрегировать в подзапросы:

select 
    o.order_id, 
    sa.shipping_name as user,
    round(op.value - coalesce(od.value, 0), 2) order_total
from orders o
inner join (
    select order_id, sum(price * amount) value
    from order_products op
    group by order_id
) op on op.order_id = o.order_id
left join (
    select order_id, sum(discount) value
    from order_discounts 
    group by order_id
) od on od.order_id = o.order_id
left join shipping_addresses sa 
    on o.shipping_address_id = sa.shipping_address_id 
order by o.order_date desc, o.user_id desc

Вы также можете использовать подзапросы:

select
    o.order_id,
    sa.shipping_name as user,
    round(
        (
            select sum(op.price * op.amount) 
            from order_products op 
            where op.order_id = o.order_id
        ) 
        - (
            select coalesce(sum(od.discount), 0)
            from order_discounts od
            where od.order_id = o.order_id
        ),
        2
    ) order_total
from orders o
left join shipping_addresses sa 
    on o.shipping_address_id = sa.shipping_address_id 
order by o.order_date desc, o.user_id desc
...