В Ada (и я верю большинству других Полученных из Алгола языков) завершающееся условие "для" цикла оценено только однажды, в начале цикла. Например, предположите, что у Вас есть следующий код в Ada
q := 10;
for i in 1..q loop
q := 20;
--// Do some stuff
end loop;
, которого Этот цикл выполнит итерации точно 10 раз, потому что q равнялся 10 когда запущенный цикл. Однако, если я пишу на вид эквивалентный цикл в C:
q = 10;
for (int i=0;i<q;i++) {
q = 20;
// Do some stuff
}
Тогда цикл выполняет итерации 20 раз, потому что q был изменен на 20 к тому времени, когда я стал достаточно крупным для него для имения значение.
путь C более гибок, конечно. Однако это имеет довольно много отрицательных последствий. Очевидное - то, что программа должна потратить впустую усилие, перепроверяющее, что цикл обусловливает каждый цикл. Хороший оптимизатор мог бы быть достаточно умным для работы вокруг проблемы в простых случаях как это, но что происходит, если "q" является глобальным, и "делают некоторый материал" включает вызов процедуры (и таким образом в теории мог изменить q)?
неопровержимый факт - то, что мы просто знаем путь [еще 112] о цикле Ada, чем мы делаем о цикле C. Это означает, что с тем же уровнем аналитики и усилия в его оптимизаторе, Ada может сделать намного лучшее задание оптимизации. Например, компилятор Ada знает, что может заменить весь цикл 10 копиями содержания, неважно, каково то содержание. Оптимизатор C должен был бы исследовать и проанализировать содержание.
Это - на самом деле только один из многих путей, где дизайн синтаксиса C зажимает в тиски компилятор.
Я не уверен, что понял вас, но это может быть то, что вы ищете:
SELECT i.invoiceid, sum(case when i.amount is not null then i.amount else 0 end), sum(case when i.amount is not null then i.amount else 0 end) - sum(case when p.amount is not null then p.amount else 0 end) AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN payments p ON ip.paymentid = p.paymentid
LEFT JOIN customers c ON p.customerid = c.customerid
WHERE c.customernumber = '100'
GROUP BY i.invoiceid
Это даст вам суммы сумм, если для каждого счета есть несколько строк оплаты
Во-первых, разве не должно быть CustomerId в таблице Invoices? Как бы то ни было, вы не можете выполнить этот запрос для счетов-фактур, по которым еще нет платежей. Если в счете-фактуре нет платежей, этот счет-фактура даже не будет отображаться в выводе запроса, даже если это внешнее соединение ...
Кроме того, когда покупатель производит платеж, как узнать, какой счет-фактура прикрепить к? Если единственный способ - использовать InvoiceId в квитанции, которая поступает с платежом, то вы (возможно, ненадлежащим образом) связываете счета-фактуры с заказчиком, который их оплатил, а не с заказчиком, который их заказал .... (Иногда счет может быть оплачен кем-то, кроме клиента, заказавшего услуги)
Большое спасибо за ответы!
Saggi Malachi, этот запрос, к сожалению, суммирует сумму счета в случаях, когда существует более одного платежа. Допустим, есть два платежа по счету на 39 долларов: 18 и 12 долларов. Таким образом, вместо того, чтобы получить результат, который выглядит примерно так:
1 39.00 9.00
Вы получите:
1 78.00 48.00
Charles Bretana, в ходе сокращения моего запроса до простейшего из возможных запросов я (по глупости) пропустил дополнительную таблицу, customerinvoices, которая обеспечивает связь между клиентами и счетами. Это можно использовать для просмотра счетов-фактур, по которым не производились платежи.
После долгих усилий я думаю, что следующий запрос вернет то, что мне нужно:
SELECT DISTINCT i.invoiceid, i.amount, ISNULL(i.amount - p.amount, i.amount) AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN customerinvoices ci ON i.invoiceid = ci.invoiceid
LEFT JOIN (
SELECT invoiceid, SUM(p.amount) amount
FROM invoicepayments ip
LEFT JOIN payments p ON ip.paymentid = p.paymentid
GROUP BY ip.invoiceid
) p
ON p.invoiceid = ip.invoiceid
LEFT JOIN payments p2 ON ip.paymentid = p2.paymentid
LEFT JOIN customers c ON ci.customerid = c.customerid
WHERE c.customernumber='100'
Вы, ребята, согласны?
У меня есть совет для тех, кто хочет получить различные агрегированные значения из одной таблицы.
Допустим, у меня есть таблица с пользователями и таблица с баллами, которые приобретают пользователи. Таким образом, связь между ними 1:N (один пользователь, много записей о баллах).
Теперь в таблице 'points' я также храню информацию о том, за что пользователь получил очки (логин, клик по баннеру и т.д.). И я хочу вывести список всех пользователей, упорядоченный по SUM(points)
И затем по SUM(points WHERE type = x)
. То есть упорядочить по всем очкам, которые есть у пользователя, а затем по очкам, которые пользователь получил за определенное действие (например, вход в систему).
SQL будет выглядеть так:
SELECT SUM(points.points) AS points_all, SUM(points.points * (points.type = 7)) AS points_login
FROM user
LEFT JOIN points ON user.id = points.user_id
GROUP BY user.id
Вся прелесть этого в SUM(points.points * (points.type = 7))
, где внутренняя скобка оценивается либо в 0, либо в 1, таким образом умножая данное значение очков на 0 или 1, в зависимости от того, соответствует ли оно нужному нам типу очков.