SELECT Projects.Projectid, Projects.ProjectNumber, Projects.ProjectName,
Projects.ProjectBudgetedIS, Projects.ProjectSpentIS,
Projects.ProjectBudgetedBusiness, Projects.PorjectSpentBusiness, Project.Status,
ProjectStatus.Status AS Expr1
FROM Projects
INNER JOIN ProjectStatus ON Projects.Status = ProjectStatus.StatusID
WHERE Projects.Status = #Status
So what I want to do is take the sum of a table called invoices which has a field called ISorBusiness and a field called totalspent and store that data into the projects tabel in the appropriate field. So that when I get an invoice that is charged to the IS it takes that amount and rolls it into the Projects.ProjectSpentIS and if I get a invoice that is to the business it rolls it into the Projects.ProjectBudgetedBusiness.
I know this should be easy and sorry for the noobish question. Thanks in advance!
I would do something like:
SELECT SUM(CASE WHEN (IsOrBusiness = 'IS') THEN totalSpent ELSE 0 END) AS IsSpent,
SUM(CASE WHEN (IsOrBusiness = 'Business') THEN totalSpent ELSE 0 END) AS BusinessSpent
FROM Invoices
Obviously the usage depends on whether you are trying to write an insert query or select this data as part of the select query you have posted.
Related
I have a question: what is the right way to use a CASE statement in the ON clause of a JOIN?
(I saw a couple of similar questions had been asked by others, but I don't see how to replicate the solutions in my scenario.)
I try to connect 2 instances of the same table (self join).
The table contains a balance value of each customer for each day (row per customer per day, each customer appears multiple times- since the first day of his activity and till he/she closes the account)
For each customer i need to find what is the balance today and in another column - what was the balance on the "base date". The default for the base date is the 31 -dec-2019 BUT if the customer comes from a specific branch (BRANCH "X") then the base date should be 31-mar-2020 (instead of 31-dec-2019).
So what I'm trying to do is to write something like this:
select
B.branch_name,
B.customer_id,
B.balance as current_balance,
B1.balance as base_date_balance,
from
balance B inner join balance B1
on B.customer_id=B1.customer_id
and B.date = '20apr2020'
and B1.date= (case when B.branch_name = 'X' then '31-mar-2020' else '31-dec-2019' end)
I get that this is not the right way to do this, but I can't figure it out what the right way is.
Thanks in advance for all the answers and the help, highly appreciate ! :)
Use window functions!:
select b.*,
max(case when branch = 'B' and date = date '2019-03-31' then balance
when date = date '2019-12-31' then balance
end) over (partition by customer_id, branch_name
) as base_date_balance
from balance b;
This should have better performance than a JOIN with an OR or CASE condition.
Alternatively, the join would look like:
from b join
b bbase
on bbase.customer_id = b.customer_id and
bbase.branch_name = b.branch_name and
( (bbase.branch_name = 'B' and bbase.date = date '2019-03-31') or
(bbase.branch_name <> 'B' and bbase.date = date '2019-12-31')
)
Select b.* from table
where rownum=1
and date<(select date from table where cust=... order by date desc)
order by date desc
This will give you the previous transaction according to the criteria. The subquery returns the latest transaction.
The next step will depend on the database. On Oracle you use:
Select (select latest_transactions)-(select previous_tranaction) from dual.
If you need more info let me know. I am writing from my phone.
Retrieve the total number of orders made and the number of orders for which payment has been done(delivered).
TABLE ORDER
------------------------------------------------------
ORDERID QUOTATIONID STATUS
----------------------------------------------------
Q1001 Q1002 Delivered
O1002 Q1006 Ordered
O1003 Q1003 Delivered
O1004 Q1006 Delivered
O1005 Q1002 Delivered
O1006 Q1008 Delivered
O1007 Q1009 Ordered
O1008 Q1013 Ordered
Unable to get the total number of orderid i.e 8
select count(orderid) as "TOTALORDERSCOUNT",count(Status) as "PAIDORDERSCOUNT"
from orders
where status ='Delivered'
The expected output is
TOTALORDERDSCOUNT PAIDORDERSCOUNT
8 5
I think you want conditional aggregation:
select count(*) as TOTALORDERSCOUNT,
sum(case when status = 'Delivered' then 1 else 0 end) as PAIDORDERSCOUNT
from orders;
Try this-
SELECT COUNT(ORDERID) TOTALORDERDSCOUNT,
SUM(CASE WHEN STATUS = 'Delivered' THEN 1 ELSE 0 END ) PAIDORDERSCOUNT
FROM ORDER
You can also use COUNT in place of SUM as below-
SELECT COUNT(ORDERID) TOTALORDERDSCOUNT,
COUNT(CASE WHEN STATUS = 'Delivered' THEN 1 ELSE NULL END ) PAIDORDERSCOUNT
FROM ORDER
you could use cross join between the two count
select count(orderid) as TOTALORDERSCOUNT, t.PAIDORDERSCOUNT
from orders
cross join (
select count(Status) PAIDORDERSCOUNT
from orders where Status ='Delivered'
) t
What I've used in the past for summarizing totals is
SELECT
count(*) 'Total Orders',
sum( iif( orders.STATUS = 'Delivered', 1, 0 ) ) 'Total Paid Orders'
FROM orders
I personally don't like using CASE WHEN if I don't have to. This logic may look like its a little too much for a simple summation of totals, but it allows for more conditions to be added quite easily and also just involves less typing, at least for what I use this regularly for.
Using the iif( statement to set up the conditional where you're looking for all rows in the STATUS column with the value 'Delivered', with this set up, if the status is 'Delivered', then it marks it stores a value of 1 for that order, and if the status is either 'Ordered' or any other value, including null values or if you ever need a criteria such as 'Pending', it would still give an accurate count.
Then, nesting this within the 'sum' function totals all of the 1's denoted from your matched values. I use this method regularly for report querying when there's a need for many conditions to be narrowed down to a summed value. This also opens up a lot of options in the case you need to join tables in your FROM statement.
Also just out of personal preference and depending on which SQL environment you're using this in, I tend to only use AS statements for renaming when absolutely necessary and instead just denote the column name with a single quoted string. Does the same thing, but that's just personal preference.
As stated before, this may seem like it's doing too much, but for me, good SQL allows for easy change to conditions without having to rewrite an entire query.
EDIT** I forgot to mention using count(*) only works if the orderid's are all unique values. Generally speaking for an orders table, orderid is an expected unique value, but just wanted to add that in as a side note.
SELECT DISTINCT COUNT(ORDERID) AS [TOTALORDERSCOUNT],
COUNT(CASE WHEN STATUS = 'ORDERED' THEN ORDERID ELSE NULL END) AS [PAIDORDERCOUNT]
FROM ORDERS
TotalOrdersCount will count all distinct values in orderID while the case statement on PaidOrderCount will filter out any that do not have the desired Status.
I apologize if I can't explain myself clearly but I'll try my best.
So I need to query a table (money transactions) where in a certain, say branch R1 sends money to another branch (can be any branch (R1 - R2000)). I need to be able to get the count of transactions (money sent). The problem is that there are too many branches (2000+ branches).
The table looks like this:
This is how the results should look like this:
I did the same query with this before but there were only less than 20 branches that were considered. I did something like this.
SELECT
SUM(CASE WHEN BranchCode = 'R1' THEN 1 ELSE 0 END) 'R1',
SUM(CASE WHEN BranchCode = 'R2' THEN 1 ELSE 0 END) 'R2',
.....
SUM(CASE WHEN BranchCode = 'R20' THEN 1 ELSE 0 END) 'R20'
FROM MoneyTable
I want to know if I can be able to do this in a more efficient way.
It's hard to say without more information, such as what your table looks like, but assuming that each for each row, the value in column BranchCode indicates that a particular branch sent money, and you just want to count the number of transactions that the branch sent to any other branch the query would look something like this.
select sending_branch, count(*)
from moneytable
group by 1
Assuming you wanted transaction counts from one branch to another, then something like this.
select sending_branch, receiving_branch, count(*)
from moneytable
group by 1,2
Similarly if you wanted amounts
select sending_branch, receiving_branch, sum(amount)
from moneytable
group by 1,2
I am trying to write a query that shows 3 different columns. The activity class name, total revenue, and number of customers. My code below shows those columns (along with 2 different prices, student and regular). What I am trying to do is write a query that calculates revenue based on what the customer type is * the appropriate customer type (student or regular). I can't seem to be write the query to distinguish the 2 different customer types and the appropriate price into a 'revenue' column. Any help would be much appreciated!
SELECT ACTIVITY_NAME AS CLASS,
STUDENT_PRICE,
REGULAR_PRICE,
Count(CUSTOMER.CUSTOMER_TYPE) AS NUM_CUST,
Count(CUSTOMER.CUSTOMER_TYPE) * ACTIVITY.STUDENT_PRICE AS REVENUE
FROM ACTIVITY
JOIN ACTIVITY_BOOKING
ON ACTIVITY.ID = ACTIVITY_BOOKING.ACTIVITY_ID
JOIN CUSTOMER
ON ACTIVITY_BOOKING.CUSTOMER_ID = CUSTOMER.ID
GROUP BY ACTIVITY_NAME,
STUDENT_PRICE,
REGULAR_PRICE
ORDER BY ACTIVITY.ACTIVITY_NAME
I think you need SUM not COUNT and you can sum conditional value as:
SELECT ACTIVITY_NAME AS CLASS,
STUDENT_PRICE,
REGULAR_PRICE,
Count(CUSTOMER.CUSTOMER_TYPE) AS NUM_CUST,
Sum (case when CUSTOMER.CUSTOMER_TYPE = 'Student' then STUDENT_PRICE when CUSTOMER.CUSTOMER_TYPE = 'Regular' then REGULAR_PRICE else 0 end) AS REVENUE
FROM ACTIVITY
JOIN ACTIVITY_BOOKING
ON ACTIVITY.ID = ACTIVITY_BOOKING.ACTIVITY_ID
JOIN CUSTOMER
ON ACTIVITY_BOOKING.CUSTOMER_ID = CUSTOMER.ID
GROUP BY ACTIVITY_NAME,
STUDENT_PRICE,
REGULAR_PRICE
ORDER BY ACTIVITY.ACTIVITY_NAME
Quick question if anyone has time to answer. The current query works great, but I need to also get a total count of the orders and the total shipping. I know the numbers are getting thrown off because of the joins.
I know that my count and sum will be:
count(DISTINCT orders.id) AS num_orders,
SUM(orders.shipping_cost_ex_tax) AS shipping
I think I need to use the count and sum in the original select and handle the rest in the join, but for the life of me I can't get this right.
Any help would be appreciated, even if it's "run a separate query". Thanks everyone.
Current query:
SELECT
IF(products.categories LIKE '68', 'Shirts', 'Books') AS group_key,
CONCAT(order_products.name) AS product_name,
brands.name AS author,
SUM(order_products.quantity) AS num_units,
CASE WHEN products.sku LIKE '%-WB' THEN 'Combo'
WHEN products.sku LIKE '%-BO' THEN 'Box'
ELSE ''
END AS item_type,
SUM(IF(order_products.discount IS NULL, order_products.price_ex_tax, (order_products.price_ex_tax - order_products.discount))) AS income
FROM orders
INNER JOIN order_products ON order_products.bc_order_id = orders.bc_id
INNER JOIN products ON order_products.bc_product_id = products.bc_id
INNER JOIN brands ON products.brand_id = brands.bc_id
WHERE (orders.created_at BETWEEN '2012-01-28 00:00:00' and '2012-02-21 23:00:00')
GROUP BY group_key,
case when products.brand_id = '68'
then products.name
else products.sku
end
Looking at the comment provided and not having your full schema in front of me. Would something like this work:
Table Report
(
id,
countOrders,
countSales,
countShipping,
countTax,
datePublished
)
Table SoldProducts
(
id,
price,
tax,
shippingPrice,
datePurchased
)
So what you would do in this instance is generate a report by querying from SoldProducts then you would persist the report that was generated.