MYSQL Query WITH a subQ - mysql

I am trying to grab all of the SUMS for columns, as I am doing this I want to JOIN the shipped filed so I am only grabbing SUMS of current orders that have not shipped. From my efforts I keep getting a result in which all the columns are wrong amounts calculated. THANK YOU IN ADVANCE.
I believe I need to write a subQ, but I am having issues trying to get there.
If I remove the JOIN, the result is perfect, no problems, but I need the join so I am only calculating non shipped items. I believe its pulling some other records from the join table. THANK YOU IN ADVANCE.
SELECT XX.order_num, XX.shipped, PP.order_num AS JON, PP.part_num AS JPT, SUM(PP.total_qty) AS QTY, SUM(PP.work_time) AS WT,SUM(PP.setup_time) AS ST,SUM(PP.scrap) AS SC
FROM PP
JOIN XX
ON XX.order_num = PP.order_num
WHERE PP.department='RIBBON'
AND PP.ribbon_type='CRIMPING' AND XX.shipped IS NULL
GROUP BY part_num
ORDER BY PP.order_num DESC
I am getting this:
so185702 6609628 8,120 92.67 HRS 1.92 HRS 0
When it should read this:
so185702 6609628 760 545 15 0
I just need help in writing the subQ, I am still a beginner. THANK YOU.

When you mix normal columns with aggregate functions (like sum), you need the GROUP BY-clause where you list all columns in SELECT which do not have the aggregate function. In your query the first four columns:
SELECT
XX.order_num,
XX.shipped,
PP.order_num AS JON,
PP.part_num AS JPT,
SUM(PP.total_qty) AS QTY,
SUM(PP.work_time) AS WT,
SUM(PP.setup_time) AS ST,
SUM(PP.scrap) AS SC
FROM PP
JOIN XX ON XX.order_num = PP.order_num
WHERE PP.department='RIBBON' AND PP.ribbon_type='CRIMPING' AND XX.shipped IS NULL
GROUP BY XX.order_num, XX.shipped, PP.order_num, PP.part_num
ORDER BY PP.order_num DESC

Related

Postgresql query / Group by and sum

Just joined the group yesterday, and have already received great advice from the community. I have another scenario I need a bit of a push with. The advice I received yesterday resolved my first issue, but I have a 2nd scenario I would like to try implementing.
I have the following Postgresql query that converts a "size" value from a json column type from bytes to MB:
SELECT c.name AS customer, i.customer_id, i.captured_at, i.name AS image,
i.raw_upload_complete
, pg_size_pretty((i.manifest ->> 'size')::numeric) AS image_size
FROM public.images i
JOIN public.customers c ON c.id = i.customer_id
WHERE i.raw_upload_complete = 'true' AND captured_at > date_trunc('day', now()) -
interval '2 months'
ORDER BY customer ASC
Here is an example of the output:
Customer Customer ID captured_at image raw_upload_complete image_size
Customer 1 250 2022-05-09 Ventures Pit TRUE 4044 MB
Customer 1 250 2022-06-01 Ventures Pit TRUE 500 MB
Customer 2 85 2022-04-18 Devault Quarry TRUE 672 MB
Customer 2 85 2022-05-02 Talmage Quarry TRUE 3876 MB
The query works great, however, what I would like to do is group the result set by Customer, and SUM the image_size for each customer. So in the above example, I'd like to have the customers grouped as they are, and reflect customer 1 has a total image size of 4544 MB, and Customer 2 has a total image size of 4548 MB. Ideally I'd like each customer summarized on one line, or in some kind of high-level rolled-up fashion.
I mentioned in my first post I am fairly new at SQL so the solutions could be obvious, but I've been struggling with this one. I've tried the crosstab function to no avail, but I'm not sure if there is a better option. The thing that seems to have been giving me issues is that the image_size column that was created comes out as TEXT, not numeric, which has been causing issues. I have been using Google Data Studio and thought simply changing the data type would help, but even though it would let me change it to a number, it was still being recognized as a text field.
Thanks very much.
I'm going to work this backwards. First, let's write a query that gets the total image size by customer
select c.id, pg_size_pretty(sum((i.manifest ->> 'size')::numeric)) as total
from images i
join customers c on i.customer_id = c.id
where [snippped]
group by c.id
Note that you want to do the sum(), and then apply pg_size_pretty. That's because the results of pg_size_pretty() will have the "MB", "GB" stuff inside, so it's actually text and not a number anymore.
Now we can use that query as a CTE to get the result you want
with total_size as (
select c.id, pg_size_pretty(sum((i.manifest ->> 'size')::numeric)) as total
from images i
join customers c on i.customer_id = c.id
where [snippped]
group by c.id
) as total
SELECT c.name AS customer, i.customer_id, i.captured_at, i.name AS image,
i.raw_upload_complete
, total_size.total
FROM public.images i
JOIN public.customers c ON c.id = i.customer_id
JOIN total_size on c.id = total_size.id
WHERE i.raw_upload_complete = 'true' AND captured_at > date_trunc('day', now()) -
interval '2 months'
ORDER BY customer ASC
So if you look carefully, you'll see that we have the additional join to the "total" CTE, and that the SELECT clause uses the "total" value from the CTE.
The reason why you have to do this in two steps is that your desired result mixes detailed image data (e.g. "captured_at") with summary image data (the total size). That kind of mixing trips up a lot of people who are learning SQL.

MYSQL query to get project details and last MAX() action details from log

How can I write a MYSQL query to get project details and the entire last row of the activity log? I want a list of all the projects, with the data from each project's most recent row from the action log, all of it ordered by the most recent action log date DESC. Sorry, I know that this is a common query and the answer must be very easy. But I can't find the solution. I searched with every possible word combination. I found examples that need only one field such as MAX(id) from the joined table. I found solutions with COALESCE but can't seem to make them work. My problem is that I need many fields from the 'parent' table row PL_PROJECTS as well as many fields from the joined table PL_LOG row, not to mention people's names from the same table joined twice.
Everything I try either gives me all the rows of the PL_LOG, repeating rows from PL_PROJECTS. Or, I get just one row from PL_LOG for just one project if I put a LIMIT in the sub query. Here's my query that doesn't work:
SELECT
PJ.pj_id, PJ.pj_title, PJ.pj_location, PJ.pj_desc, PJ.pj_request, PJ.pj_date_start, PP1.pp_name AS supervisor_name, PP2.pp_name AS customer_name, ST.st_desc, logDate, logDesc
FROM PL_PROJECTS PJ
INNER JOIN PL_PEOPLE PP1 ON PJ.pj_spst_member = PP1.pp_id
INNER JOIN PL_PEOPLE PP2 ON PJ.pj_pp_id = PP2.pp_id
INNER JOIN PL_STATUS ST ON PJ.pj_status = ST.st_id
LEFT OUTER JOIN (
SELECT MAX(lg_pj_id) MaxLogID, lg_date AS logDate, lg_desc AS logDesc, lg_pj_id
FROM PL_LOG PL
ORDER BY lg_id DESC
)
LR ON LR.lg_pj_id = PJ.pj_id
GROUP BY PJ.pj_id
ORDER BY logDate DESC
LIMIT 9999999
I think you problem is, that your subselect only generates one row as you are using max() while you need one row per project (lg_pj_id i think).
You only need to rewrite the subselect to generate one row per project with the informations from the recent activity. Do you have an activity_ID in your action log? Because it looks like
lg_pj_id is the project_ID. The meaning of lg_desc is also unknown (or is that the action_log_id ?). Try to group by project_ID in you subselect and depending on your needs either select the max values from the corresponding rows or select the row with the maximum values per group (project_ID)
Thanks for the suggestion of GROUP BY to get one row per project. I tried changing the sub-query like so:
SELECT MAX(lg_id) AS MaxLogID, lg_desc, lg_pj_id
FROM PL_LOG PL
GROUP BY lg_pj_id
Now, I get one row from the log, but it gives me the max id, but not the lg_desc from the same row! If I try the sub-query by itself:
SELECT lg_id, lg_pj_id, lg_date, lg_desc
FROM `PL_LOG`
WHERE lg_pj_id = 33
ORDER BY lg_date DESC
I get these rows. You can see the max row, 68 has a description "30 minute skype call."
68,33,2018-06-10 00:00:00","30 minute skype call."
61,33,"2018-06-02 00:00:00","Sent email to try to elicit a response."
52,33,"2018-05-10 00:00:00","sent follow up email"
47,33,"2018-03-26 00:00:00","sent initial email"
46,33,"2018-03-26 00:00:00","sent initial email"
But when I try to get just that row, using GROUP BY, it gives me the max lg_id, but the first lg_desc. I need the data all from the max(lg_id) row:
SELECT MAX(lg_id) AS MaxLogID, lg_pj_id, lg_date, lg_desc
FROM PL_LOG
WHERE lg_pj_id = 33
GROUP BY lg_pj_id
ORDER BY MaxLogID DESC
Returns:
68, 33, "2018-03-26 00:00:00", "sent initial email"
Try this as mentioned in my comment:
SELECT
PJ.pj_id, PJ.pj_title, PJ.pj_location, PJ.pj_desc, PJ.pj_request,
PJ.pj_date_start, PP1.pp_name AS supervisor_name, PP2.pp_name AS
customer_name, ST.st_desc, logDate, logDesc
FROM PL_PROJECTS PJ
INNER JOIN PL_PEOPLE PP1 ON PJ.pj_spst_member = PP1.pp_id
INNER JOIN PL_PEOPLE PP2 ON PJ.pj_pp_id = PP2.pp_id
INNER JOIN PL_STATUS ST ON PJ.pj_status = ST.st_id
LEFT JOIN (SELECT lg_id, lg_date AS logDate, lg_desc AS logDesc, lg_pj_id
FROM PL_LOG AS PL
WHERE PL.lg_id=(SELECT MAX(lg_id) FROM PL_LOG AS PL_2
WHERE PL_LOG.lg_pj_id = PL_2.lg_pj_id )
LR ON LR.lg_pj_id = PJ.pj_id
GROUP BY PJ.pj_id
ORDER BY logDate DESC
LIMIT 9999999

MySQL Inner join naming error?

http://sqlfiddle.com/#!9/e6effb/1
I'm trying to get a top 10 by revenue per brand for France on december.
There are 2 tables (first table has date, second table has brand and I'm trying to join them)
I get this error "FUNCTION db_9_d870e5.SUM does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual"
Is my use of Inner join there correct?
It's because you had an extra space after SUM. Please change it from
SUM (o1.total_net_revenue)to SUM(o1.total_net_revenue).
See more about it here.
Also after correcting it, your query still had more error as you were not selecting order_id on your intermediate table i2 so edited here as :
SELECT o1.order_id, o1.country, i2.brand,
SUM(o1.total_net_revenue)
FROM orders o1
INNER JOIN (
SELECT i1.brand, SUM(i1.net_revenue) AS total_net_revenue,order_id
FROM ordered_items i1
WHERE i1.country = 'France'
GROUP BY i1.brand
) i2
ON o1.order_id = i2.order_id AND o1.total_net_revenue = i2.total_net_revenue
AND o1.total_net_revenue = i2.total_net_revenue
WHERE o1.country = 'France' AND o1.created_at BETWEEN '2016-12-01' AND '2016-12-31'
GROUP BY 1,2,3
ORDER BY 4
LIMIT 10`
--EDIT stack Fan is correct that the o2.total_net_revenue exists. My confusion was because the data structure duplicated three columns between the tables, including one that was being looked for.
There were a couple errors with your SQL statement:
1. You were referencing an invalid column in your outer-select-SUM function. I believe you're actually after i2.total_net_revenue.
The table structure is terrible, the "important" columns (country, revenue, order_id) are duplicated between the two tables. I would also expect the revenue columns to share the same name, if they always have the same values in them. In the example, there's no difference between i1.net_revenue and o1.total_net_revenue.
In your inner join, you didn't reference i1.order_id, which meant that your "on" clause couldn't execute correctly.
PROTIP:
When you run into an issue like this, take all the complicated bits out of your query and get the base query working correctly first. THEN add your functions.
PROTIP:
In your GROUP BY clause, reference the actual columns, NOT the column numbers. It makes your query more robust.
This is the query I ended up with:
SELECT o1.order_id, o1.country, i2.brand,
SUM(i2.total_net_revenue) AS total_rev
FROM orders o1
INNER JOIN (
SELECT i1.order_id, i1.brand, SUM(i1.net_revenue) AS total_net_revenue
FROM ordered_items i1
WHERE i1.country = 'France'
GROUP BY i1.brand
) i2
ON o1.order_id = i2.order_id AND o1.total_net_revenue = i2.total_net_revenue
AND o1.total_net_revenue = i2.total_net_revenue
WHERE o1.country = 'France' AND o1.created_at BETWEEN '2016-12-01' AND '2016-12-31'
GROUP BY o1.order_id, o1.country, i2.brand
ORDER BY total_rev
LIMIT 10

how to combine two tables and count their values as one?

I want to get the total numbers of committed crimes when combining the two tables.
But I want to count the numbers for each crime being committed and also display the values of those that has not being committed as 0, How can i achieve this using mysql?
my code:
SELECT count(offense_id)
AS totalnumber,(
select offense_description
from offense
where offense.offense_id = case_crime.offense_id
)as crimeName
from case_crime
group by offense_id
To get a list of all your offenses and the count of registered crimes, you need to use the LEFT JOIN between the two tables .... something like this SQL:
SELECT a.offense_id, a.offense_description, count(b.crime_caseid) as total
FROM offense a LEFT JOIN case_crime b
ON a.offense_id = b.offense_id
group by a.offense_id;
Here is a SQLFiddle to play around with :)
You are looking for a LEFT OUTER JOIN
Something like
SELECT offense.offense_id
, offense_description
, count(case_crime.case_id) as Total_Number
from offense
LEFT OUTER JOIN case_crime ON offense.offense_id = case_crime.offense_id
group by offense.offense_id
I'll admit, I'm a TSQL guy, so I would handle the COUNT(*) returning null when there are no cases with the specified offense using: ISNULL(COUNT(case_crime),0)
Other SQL variants might use COALESCE( COUNT(case_crime), 0)

Is the Query returning in consistent results?

Changed the question after peeling the outer layers
I am using MySQL 5.1
select s.status, street, m.meterpointid
from meterpoint m inner join account a
on ( m.accountid = a.accountid) inner join
meterservice s
on ( m.meterpointid = s.meterpointid )
where a.citystateid=1 and m.meterpointid=3008 and m.lastupdate is not null
group by status, street ;
The above query returns
1 210 S HWY 3 3008
select s.status, street, m.meterpointid
from meterpoint m inner join account a
on ( m.accountid = a.accountid) inner join
meterservice s
on ( m.meterpointid = s.meterpointid )
where a.citystateid=1 and m.lastupdate is not null
group by status, street ;
but the output from above query which is exactly the same as the previous query without the m.meterpointid=3008 does not contain the 1 210 S HWY 3 3008
Any ideas?
Thanks
Naren
The change on the inner query is changing the count in the outer query, so having count(*) = 1 is no longer true. I find the best way to diagnose these sorts of things is to peel away outer layers and look at the inner queries until I figure out what is going on.
This is not at all surprising. You are using a (mis)feature of MySQL called Hidden Columns. That is, you have columns in the select clause that are not in the group by clause and are not in aggregation functions.
In this case, an arbitrary value is chosen for the value.
To fix this problem, either do:
group by status, street, m.meterpointid
or
select s.status, street, min(m.meterpointid)
These will fix the query so the results are determinate.
Not including the test m.meterpointid=3008 can change the count. If, according to count(*) = 1, the count is not 1 the result is discarded. If the subselect of the second query returns more than one record, then this result will be discarded.