Чи можу я повторно використовувати обчислене поле в запиті SELECT?


78

Чи є спосіб повторного використання обчисленого поля в операторі mysql. Я отримую помилку "невідомий стовпець total_sale" для:

SELECT 
    s.f1 + s.f2 as total_sale, 
    s.f1 / total_sale as f1_percent
FROM sales s

або мені доведеться повторити обчислення, що зробило б дуже довгий оператор SQL, якби я додав усі необхідні обчислення.

SELECT 
    s.f1 + s.f2 as total_sale, 
    s.f1 / (s.f1 + s.f2) as f1_percent
FROM sales s

звичайно, я можу робити всі обчислення у своїй програмі php.


"звичайно, я можу виконати всі обчислення в моїй програмі на php" - це буде не найгіршою ідеєю.
Пол Шпігель,

Відповіді:


83

Так, ви можете повторно використовувати змінні. Ось як ви це робите:

SELECT 
    @total_sale := s.f1 + s.f2 as total_sale, 
    s.f1 / @total_sale as f1_percent
FROM sales s

Детальніше про це читайте тут: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html

[Примітка: Ця поведінка не визначена. Згідно з документами MySQL:]

Як загальне правило, ви ніколи не повинні призначати значення користувацькій змінній і читати значення в тому самому операторі. Ви можете отримати очікувані результати, але це не гарантується.


@OMG Поні Розум розробляє? "@total_sale: =" це недостатньо декларації?
rzetterberg

Це встановлює змінну, а не оголошує її. Декларування означає або використання SETоператора, або похідної таблиці / вбудованого подання.
OMG Ponies

2
"Ви також можете призначити значення змінній користувача в операторах, відмінних від SET. У цьому випадку оператором присвоєння має бути: = а не =, оскільки останній обробляється як оператор порівняння = у операторах, що не входять у SET:"
rzetterberg

13
@OMGPonies (та інші) Це не підтримується: "За загальним правилом, ви ніколи не повинні призначати значення користувацькій змінній і читати значення в тому самому твердженні. Ви можете отримати очікувані результати, але це не гарантується." Це працює, як і, працює. Але результати можуть бути невірними.
Аріель

3
Коли я намагаюся використовувати це з груповою функцією (наприклад, SUMабо COUNT, я отримую протиінтуїтивний і непотрібний результат, що змінні завжди мають значення попереднього рядка, а не рядка, на якому я перебуваю. Це не підтримується з поважних причин і повинно бути уникати.
Девід Родимки

64

Наступне, здається, добре працює при моєму тестуванні на MySQL 5.5:

SELECT 
    s.f1 + s.f2 as total_sale, 
    s.f1 / (SELECT total_sale) as f1_percent
FROM sales s

5
Мені подобається це. Безумовно, найкраща читабельність серед усіх відповідей і відсутність попереджень щодо використання в документації mysql. Однак його не можна використовувати для посилання на результати групи, такі як ті, які ви отримуєте за допомогою SUM або COUNT.
Девід

3
Оскільки поточна прийнята відповідь не могла працювати щоразу, це може бути прийнятою відповіддю
Робін Чоффарде

1
Я щойно протестував на MariaDB 10.1.24 з наступним, і він спрацював чудово. ВИБЕРИТЕ Price_Per_SqFt, (Price_Per_SqFt / 2) AS col1, (SELECT col1 + 1) AS col2 FROM Items LIMIT 100
Robert D

4
Зверніть увагу, що це може працювати з простою арифметикою, але не працює з наприклад, SUMабо COUNT: ви отримаєтеreference '[colname]' not supported (reference to group function)
Девід Моулз

Це також не спрацьовує, якщо назва стовпця, яку ви обираєте, поділяє ім’я з іншим фактичним стовпцем у будь-якій з таблиць (із таблиць або об’єднаних таблиць)
Брайан Лейшман,

14

Тільки крос-платформні засоби, що підтримуються, - це використання похідної таблиці / вбудованого подання:

SELECT x.total_sale,
       x.f1 / x.total_sale as f1_percent
  FROM (SELECT s.f1,
               s.f1 + s.f2 as total_sale, 
          FROM sales s) x

8

Ви можете використовувати підвибір:

select tbl1.total_sale,
       tbl1.f1/tbl1.total_sale as f1_percent 
  from (select s.f1+s.f2 AS total_sale, 
               s.f1 
          from sales s) as tbl1;

5

Ви можете використовувати підзапити, наприклад:

SELECT 
    h.total_sale, 
    s.f1 / h.total_sale AS f1_percent
FROM sales s,
    (SELECT id, f1 + f2 AS total_sale FROM sales) h
WHERE
    s.id = h.id

Редагувати:
фіксований декартовий продукт, припускаючи, що первинним ключем є id.
Це має бути еквівалентно рішенню OMG Ponies після оптимізації, але я думаю, це стане важче читати, якщо вам потрібно більше підзапитів.


2

Я тут подивився різні відповіді та зробив кілька експериментів.

Зокрема, я використовую MariaDB 10.1.

Для "простої" речі ви можете зробити те, що запропонував Роберт Д у своєму коментарі:

SELECT Price_Per_SqFt, (Price_Per_SqFt/2) AS col1, (SELECT col1 + 1) AS col2 FROM Items 

Якщо ви використовуєте якусь сукупну функцію з внутрішнім об’єднанням, ви не можете використовувати це, але ви можете комбінувати цей підхід із внутрішнім підходом наступним чином (NB ПДВ = "податок з продажу" ... і NB у валюті фінансових даних поля зазвичай мають 4 знаки після коми, я думаю, це історично ...)

SELECT 
    invoices.invoiceNo, invoices.clientID, invoices.Date, invoices.Paid, 
  invoicesWithSubtotal.Subtotal,
  ROUND( CAST( Subtotal * invoices.VATRate AS DECIMAL( 10, 4 )), 2 ) AS VAT,
  (SELECT VAT + Subtotal) AS Total
FROM invoices 
    INNER JOIN 
    ( SELECT Sum( invoiceitems.Charge ) AS Subtotal, invoices.InvoiceNo FROM invoices 
        INNER JOIN invoiceitems ON invoices.InvoiceNo = invoiceitems.InvoiceNo
            GROUP BY invoices.InvoiceNo ) invoicesWithSubtotal
    ON invoices.InvoiceNo = invoicesWithSubtotal.InvoiceNo

Я хотів використати вищезазначене для створення Viewрахунків-фактур з їх проміжними підсумками, ПДВ та підсумками ... виявилося, що MariaDB (і майже напевно MySQL) не дозволяють вкладатись у FROMпункт. Однак це легко вирішити, зробивши перший, Viewякий перелічує InvoiceNoі Subtotal, а потім робить другий, Viewякий посилається на перший. З точки зору продуктивності я взагалі не маю уявлення про подібне подвійне Viewрозташування.


0

Я тестував наступне, і це, здається, працює весь час, можливо, для цього є причина, тому що я визначив змінну @total_sales як значення, а не рядок, і не перевизначив її тип під час вибору заява ??

Якщо я зроблю наступне

    set @total_sales = 0;

    SELECT 
       @total_sale := s.f1 + s.f2 as total_sale, 
      s.f1 / @total_sale as f1_percent
   FROM sales s

Основною проблемою змінних є не введення тексту, а порядок виконання. У документі зазначено, що "крім операторів SET, ніколи не слід призначати значення користувацькій змінній і читати значення в тому самому операторі. Ви можете отримати очікувані результати, але це не гарантується (...) порядок оцінки для виразів, що включають користувацькі змінні, не визначено. ". У вашому прикладі @total_sales може мати правильне значення при обчисленні f1_percent, але воно також може мати значення попереднього рядка.
Ейно
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.