msAccess query with Sum and extra criteria - ms-access

I need to get all of the Costs values for a Dog in a specific month. When I use this code with Access it says the join operation is not supported. Is there a better way to accomplish this in MS Access? I need all of the dog names to come back even if they don't have a cost associated with them for a specific month
Select Dog.DogName, Dog.DogOwner, Sum(Costs.CostAmount)
From
(Dog Left join Costs on Dog.DogName = Costs.DogName and Costs.CostMonth = 10)
Group by Dog.DogName, Dog.OwnerName

Try this:
Select
Dog.DogName, Dog.DogOwner, Sum(Costs.CostAmount) As TotalAmount
From
Dog
Left join
Costs
On
(Dog.DogName = Costs.DogName)
Where
Costs.CostMonth <= Month(Date())
Or
Costs.CostMonth Is Null
Group by
Dog.DogName, Dog.OwnerName

SELECT Dogs.DogName
, Dogs.OwnerName
, (
SELECT SUM(Costs.CostAmountAmount)
FROM Costs
WHERE Dogs.DogName = Costs.DogName AND
Costs.CostMonth =NumMonth
)
FROM Dogs;

Related

Use the result of a sub-query outside of the sub-query

I have a table structured like this.
User_id
Subscription_type
timestamp
100
PAYING
2/10/2021
99
TRIAL
2/10/2021
100
TRIAL
15/9/2021
I want my output to be the same, with an additional column pulling the trial start date when the subscriber converts to a paying subscription.
User_id
Subscription_type
timestamp
Trial_Start_date
100
PAYING
2/10/2021
15/9/2021
99
TRIAL
2/10/2021
100
TRIAL
2/10/2021
At the moment, I have this query:
SELECT *,
CASE WHEN
(SELECT `subscription_type` FROM subscription_event se1
WHERE se1.`timestamp` < se.`timestamp` AND se1.user_id = se.user_id
ORDER BY user_id DESC LIMIT 1) = 'TRIAL'
then se1.`timestamp` else 0 end as "Converted_from_TRIAL"
FROM subscription_event se
I have an error message with se1.timestamp not been defined. I understand why, but I cannot see a workaround.
Any pointer?
If you need to get two values out of the subquery, you have to join with it, not use it as an expression.
SELECT se.*,
MAX(se1.timestamp) AS Converted_from_TRIAL
FROM subscription_event AS se
LEFT JOIN subscription_event AS se1 ON se.user_id = se1.user_id AND se1.timestamp < se.timestamp AND se1.subscription_type = 'TRIAL'
GROUP BY se.user_id, se.subscription_type, se.timestamp
Thanks a lot!
For some reasons I needed to declare explicitely in SELECT the variables used in the GROUP BY . Not sure why ( I am using MySQL5.7 so maybe it is linked with that).
In any case, this is the working query.
SELECT se.user_id, se.subscription_type, se.timestamp,
MAX(se1.timestamp) AS Converted_from_TRIAL
FROM subscription_event AS se
LEFT JOIN subscription_event AS se1 ON se.user_id = se1.user_id AND se1.timestamp < se.timestamp AND se1.subscription_type = 'TRIAL'
GROUP BY se.user_id, se.subscription_type, se.timestamp

How select count distinct (unique truckers) without group by function and maybe without using Having (not sure about last)

I have a task, but couldn't solve it:
There are truckers and they have to travel between cities.
We have data of these travels in our database in 2 tables:
trucker_traffic
tt_id (key)
date
starting_point_coordinate
destination_coordinate
traveller_id
event_type ('travel', 'accident')
parent_event_id (For 'accident' event type it's tt_id of the original travel. There might be few accidents within one travel.)
trucker_places
coordinate (key)
country
city
I need SQL query to pull the number of all unique truckers who travelled more than once from or to London city in June 2020.
In the same query pull the number of these travels who got into an accident.
Example of my tries
SELECT
count(distinct(tt.traveller_id)),
FROM trucker_traffic tt
JOIN trucker_places tp
ON tt.starting_point_coordinate = tp.coordinate
OR tt.destination_coordinate = tp.coordinate
WHERE
tp.city = 'London'
AND month(tt.date) = 6
AND year(tt.date) = 2020
GROUP BY tt.traveller_id
HAVING count(tt.tt_id) > 1
But it's select count distinct truckers with grouping and works only if I had one tracker in db
For second part of task (where I have select number of travels with accident - I think that good to use function like this
SUM(if(count(tt_id = parent_event_id),1,0))
But I'm not sure
This is rather complicated, so make sure you do this step by step. WITH clauses help with this.
Steps
Find travels from and to London in June 2020. You can use IN or EXISTS in order to see whether a travel had accidents.
Group the London travels by traveller, count travels and accident travels and only keep those travellers with more than one travel.
Take this result set to count the travellers and sum up their travels.
Query
with london_travels as
(
select
traveller_id,
case when tt_id in
(select parent_event_id from trucker_traffic where event_type = 'accident')
then 1 else 0 end as accident
from trucker_traffic tt
where event_type = 'travel'
and month(tt.date) = 6
and year(tt.date) = 2020
and exists
(
select
from trucker_places tp
where tp.coordinate in (tt.starting_point_coordinate, tt.destination_coordinate)
and tp.city = 'London'
)
)
, london_travellers as
(
select
traveller_id,
count(*) as travels,
sum(accident) as accident_travels
from london_travels
group by traveller_id
having count(*) > 1;
)
select
count(*) as total_travellers,
sum(travels) as total_travels,
sum(accident_travels) as total_accident_travels
from london_travellers;
If your MySQL version doesn't support WITH clauses, you can of course just nest the queries. I.e.
with a as (...), b as (... from a) select * from b;
becomes
select * from (... from (...) a) b;
You say in the request title that you don't want GROUP BY in the query. This is possible, but makes the query more complicated. If you want to do this I leave this as a task for you. Hint: You can select travellers and count in subqueries per traveller.

How to select sql with if else use column

I'm beginner for mysql and this my graduation project please help me.
//AMOUNT_PEOPLE is variable in nodejs
//place_id is variable in nodejs recieve from front end.
SELECT
(IF AMOUNT_PEOPLE >= 10
RETURN COLUMN package_tb.price_group*(AMOUNT_PEOPLE-1)
ELSE IF AMOUNT_PEOPLE >= 6
RETURN COLUMN package_tb.price_group*(AMOUNT_PEOPLE-1) - (SELECT option_tb.price_group FROM option_tb WHERE obtion_tb.place_id = place_id)
ElSE
RETURN COLUMN price_normal*AMOUNT_PEOPLE
END IF) AS price,name,detail
FROM package_tb WHERE package_tb.place_id = place_id
This ticket booking program
Logic is
Check number of tourist
if tourist >= 10 must use group_price and free 1 person include food for free person option
but if tourist >= 6 must use group_price
and free 1 person but not include food for free person option
finally tourist 0-5 must use normal_price
Such customer tell me "I want ticket for 10 tourist" the system will check as above explain.
package_tb
-package_id
-place_id
-name
-detail
-price_group
-price_normal
option_tb
-option_id
-place_id
-name
-price_group
-price_normal
place_tb
-place_id
-name
If tourist use price group option have to use price group only
But tourist use price normal option have to use price normal only.
Sorry for my bad english.
There exists a CASE function.
Which is a standard SQL function for switch logic.
Based on the updated question I'm assuming that there can be multiple options per place.
So with node.js variables:
SET #place_id = ${PLACE_ID};
SET #amount_people = ${AMOUNT_PEOPLE};
SELECT
CASE
WHEN #amount_people >= 10
THEN (p.price_group * (#amount_people - 1))
WHEN #amount_people >= 6
THEN (p.price_group * (#amount_people - 1)) - SUM(o.price_group)
ELSE p.price_normal
END AS price,
p.name,
p.detail
FROM package_tb p
LEFT JOIN option_tb o ON o.place_id = p.place_id
WHERE p.place_id = #place_id
GROUP BY p.package_id, p.place_id, p.price_normal, p.price_group, p.name, p.detail;
A test on rextester here
-- From which table you want use price_normal? tb or o ???
SELECT
CASE WHEN p.AMOUNT_PEOPLE >= 4
THEN p.price_group
WHEN p.AMOUNT_PEOPLE >= 3
THEN p.price_group - o.price_food
ELSE tb.price_normal
END AS price,
p.name, p.detail
FROM package_tb p JOIN option_tb o ON o.package_id = p.package_id;
There are two main control-flow functions in MySQL IF() and CASE
Since you are not comparing the value of AMOUNT_PEOPLE directly, CASE is a bit of overkill, which can be simplified slightly by using IF.
The syntax for IF is IF(<expr>, <true_result>, <false_result>). This allows you to perform else if by chaining another IF() as the false_result
IF(<expr>, ..., IF(<expr>, ..., ...))
Instead of using else if, you only need to remove the option_tb.price_group when AMOUNT_PEOPLE is fewer than 10 to get your desired pricing.
/* groups with 6 or more use group price and one person free */
IF(AMOUNT_PEOPLE >= 6,
/* groups with fewer than 10 people remove option */
p.price_group*(AMOUNT_PEOPLE-1) - IF(AMOUNT_PEOPLE < 10,
o.price_group,
0
),
p.price_normal*AMOUNT_PEOPLE
) AS price
This reduces the amount of code slightly, to determine when to subtract a person.
Instead of using a nested sub-query, which would be executed for each row returned. If the option_tb.place_id is unique, a JOIN would be more preferable.
If option_tb.place_id is not unique, you would need to use a GROUP BY. One approach is to JOIN using a sub-query, to avoid false matching on the join table groupings.
To ensure results are not excluded when a row in the option_tb table fails to match a place_id, you would use a LEFT JOIN that returns NULL instead of excluding the row.
Then you can use COALESE(<column>, 0) to retrieve the value from the column or 0 if the column value is NULL.
In NodeJS you can use ${var} to inject a variable into a string.
For example:
var place_id = 1;
var query = 'SELECT ${place_id};';
console.log(query);
Results in
SELECT 1;
Putting it all together.
Example: db-fiddle
SELECT
IF(${AMOUNT_PEOPLE} >= 6,
p.price_group*(${AMOUNT_PEOPLE}-1) - IF(${AMOUNT_PEOPLE} < 10, COALESCE(o.price_group, 0), 0),
p.price_normal*${AMOUNT_PEOPLE}
) AS price,
p.name,
p.detail
FROM package_tb AS p
LEFT JOIN (
SELECT
place_id,
SUM(price_group) AS price_group
FROM option_tb
GROUP BY place_id
) AS o
ON o.place_id = p.place_id
WHERE p.place_id = ${place_id};

Combine fields of multiple tables returns too many rows when more than 1 field is used

I have the following query:
SELECT DISTINCT x.TaskID S_ID
, y.TaskID T_ID
, z.TaskID P_ID
, z.Duration
FROM SumSubTaskPDay x
LEFT
JOIN SumTaskPDay y
ON y.TaskID = x.T_ID
LEFT
JOIN SumParentTaskPDay z
ON z.TaskID = SumTaskPDay.y
The issue I'm having is that the query returns too many rows as soon as I add another field besides the ID's.
So in this example, the field SumParentTaskPDay.Duration causes the row count to quadruple more or less
The issue is probably in the tables who are actually views from 3 aliases from the same table tasks:
tasks as subtasks is linked to tasks as tasks with tasks.id = subtasks.parent_id
CREATE VIEW SumTaskPDay AS
SELECT DATE_FORMAT(n.START, '%d %M %Y') dDay
, t.idTask TaskID
, t.TaskName
, t.ParentTaskId PT_ID
, COUNT(s.idTask) SubTaskCount
, SUM(UNIX_TIMESTAMP(n.STOP) - UNIX_TIMESTAMP(n.START)) DurationUnix
, DATE_FORMAT(SEC_TO_TIME(SUM(UNIX_TIMESTAMP(n.STOP) - UNIX_TIMESTAMP(n.START))), '%H:%i:%s') Duration
FROM Slips n
LEFT
JOIN Tasks s
ON s.idTask = n.idTask
LEFT
JOIN Tasks t
ON t.idTask = s.ParentTaskId
GROUP
BY dDay
, t.idTask
, t.TaskName
, t.ParentTaskId
I use this approach to sum up the duration fields for the different levels, so I can fetch a simple view for building a report, where I only have to care about grouping, no formulas and stuff, so I can easily switch to different report building tools without hours of figuring out the way to sum and format timestamps

filed showing null value when joining table

below is my query
select C.cName,DATE_FORMAT(CT.dTransDate,'%d-%M-%Y') as dTransDate,
(c.nOpBalance+IFNULL(CT.nAmount,0)) AS DrAMount,IFNULL(CTR.nAmount,0) AS
CrAMount,((c.nOpBalance+IFNULL(CT.nAmount,0))-IFNULL(CTR.nAmount,0)) AS
Balance,CT.cTransRefType,CT.cRemarks,cinfo.cCompanyName,cinfo.caddress1,cinfo.cP
honeOffice,cinfo.cMobileNo,cinfo.cEmailID,cinfo.cWebsite from Customer
C LEFT JOIN Client_Transaction CT ON CT.nClientPk = C.nCustomerPk AND
CT.cTransRefType='PAYMENT' AND CT.cClientType='CUSTOMER' AND CT.dTransDate
between '' AND '' LEFT JOIN Client_Transaction CTR ON CTR.nClientPk =
C.nCustomerPk AND CTR.cTransRefType='RECEIPT' AND
CTR.cClientType='CUSTOMER' AND CTR.dTransDate between '2015-05-01' AND
'2015-05-29' LEFT JOIN companyinfo cinfo ON cinfo.cCompanyName like
'%Fal%' Where C.nCustomerPk = 4 Order By dTransDate
it's showing all value but dTransDate ,cTransRefType,cRemarks, showing null.
One obvious thing jumps out at us:
CT.dTransDate BETWEEN '' AND ''
^^ ^^
Another thing that jumps out at us is that there's a semi-Cartesian join between rows from CT and rows from CTR. If 5 rows are returned from CT for a given customer, and 5 rows are returned from CTR, that's going to produce a total of 5*5 = 25 rows. That just doesn't seem like a resultset that you'd really want returned.
Also, if more than one row is returned from cinfo, that's also going to cause another semi-Cartesian join. If there's two rows returned from cinfo, the total number or rows in the resultset will be doubled. It's valid to do that in SQL, but this is an unusual pattern.
The calculation of the balance is also very strange. For each row, the nAmount is added/subtracted from opening balance. On the next row, the same thing, on the original opening balance. There's nothing invalid SQL-wise with doing that, but the result being returned just seems bizarre. (It seems much more likely that you'd want to show a running balance, with each transaction.)
Another thing that jumps out at us is that you are ordering the rows by a string representation of a DATE, with the day as the leading portion. (As long as all the rows have date values in the same year and month, that will probably work, but it just seems bizarre that we wouldn't sort on the DATE value, or a canonical string representation.
I strongly suspect that you want to run a query that's more like this. (This doesn't do a "running balance" calculation. It does return the 'PAYMENT' and 'RECEIPT' rows as individual rows, without producing a semi-Cartesian result.
SELECT c.cName
, DATE_FORMAT(t.dTransDate,'%d-%M-%Y') AS dTransDate
, C.nOpBalance
, IF(t.cTransRefType='PAYMENT',IFNULL(t.nAmount,0),0) AS DrAMount
, IF(t.cTransRefType='RECEIPT',IFNULL(t.nAmount,0),0) AS CrAMount
, t.cTransRefType
, t.cRemarks
, ci.*
FROM Customer c
LEFT
JOIN Client_Transaction t
ON t.nClientPk = c.nCustomerPk
AND t.cClientType = 'CUSTOMER'
AND t.dTransDate >= '2015-05-01'
AND t.dTransDate <= '2015-05-29'
AND t.cTransRefType IN ('PAYMENT','RECEIPT')
CROSS
JOIN ( SELECT cinfo.cCompanyName
, cinfo.caddress1
, cinfo.cPhoneOffice
, cinfo.cMobileNo
, cinfo.cEmailID
, cinfo.cWebsite
FROM companyinfo cinfo
WHERE cinfo.cCompanyName LIKE '%Fal%'
ORDER BY cinfo.cCompanyName
LIMIT 1
) ci
WHERE c.nCustomerPk = 4
ORDER BY t.dTransDate, t.cTransRefTpye, t.id