MySQL Derived Table Issue - mysql

I'd like to be able to output the following fields from the query below:
AddedById,AddedByName,HoursWorked,CurrentYearlyFlexiAvailable
However where I have WHERE addedby=1, I'd like to replace this with the field name AddedById as I do not want to hard code this value as the overall query should and will return more than one person, I want to get this value from the rpt_timesheet_data view, which is there. The CurrentYearlyFlexiAvailable field should be telling me how much time they have left for the current year to date by doing the calculation between the SELECT SUM(ttl) and from the FROM (SELECT SUM(worked)-420 as ttl
SELECT AddedById,AddedByName,SUM(HoursWorked) AS HoursWorked
,(SELECT SUM(ttl) - (
SELECT SUM(worked)
FROM vwtimesheet
WHERE addedby=AddedById
AND entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND activityid=3192
GROUP BY addedby ) AS flexihours
FROM (
SELECT SUM(worked)-420 AS ttl
FROM vwtimesheet
WHERE addedby=1 <!--HERE IS THE ISSUE
AND entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND projectid<>113 AND activityid<>3192
GROUP BY entrydate
HAVING SUM(worked)>420
) AS s) AS CurrentYearlyFlexiAvailable
FROM rpt_timesheet_data
WHERE entrydate BETWEEN '2017-04-02' AND '2017-04-13 23:59:59'
AND ActivityId=3192
GROUP BY AddedById,AddedByName
ORDER BY AddedByName
but I keep getting:
Error Code: 1054. Unknown column 'AddedById' in 'where clause'
Just in that one location. I've tried various queries to sort this, but just cannot figure it out. Sorry not to good at explaining this, can see it in my head what I want to do...
Here is a query that does something very similar in that it returns the results for a single user, where as the one above is meant to loop through all users and give me the results:-
SELECT addedbyname, SUM(ttl) -
(SELECT SUM(worked)
FROM vwtimesheet
WHERE addedby=1
AND entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND activityid=3192
GROUP BY addedby ) AS CurrentYearlyFlexiAvailable
,(SELECT SUM(worked) FROM vwtimesheet
WHERE addedby=1
AND entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND activityid=3192
GROUP BY addedby ) AS flexiused
,(SELECT sum(worked) FROM vwtimesheet
WHERE addedby=1
AND entrydate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01') AND curdate()
AND activityid=3192
GROUP BY addedby ) as fleximonthused
FROM ( SELECT entrydate,addedbyname,SUM(worked)-420 AS ttl FROM vwtimesheet
WHERE addedby=1
AND entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND projectid<>113
AND activityid<>3192
GROUP BY entrydate,addedbyname
HAVING SUM(worked)>420
) AS s

Please try the following...
SELECT AddedById,
AddedByName,
SUM( HoursWorked ) AS HoursWorked,
SUM( ttl ) - sumWorked AS CurrentYearlyFlexiAvailable
FROM ( SELECT AddedById AS AddedById,
AddedByName AS AddedByName
FROM rpt_timesheet_data
GROUP BY AddedById
) AS AddedByFinder
JOIN ( SELECT addedby AS addedby,
entrydate AS entrydate,
SUM( worked ) - 420 AS ttl
FROM vwtimesheet
WHERE entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND projectid <> 113
AND activityid <> 3192
GROUP BY addedby,
entrydate
HAVING SUM( worked ) > 420
) AS ttlFinder ON AddedByFinder.AddedById = ttlFinder.addedby
JOIN ( SELECT addedby AS addedby,
SUM( worked ) AS sumWorked
FROM vwtimesheet
WHERE entrydate BETWEEN '2017-01-01' AND '2017-04-13'
AND activityid = 3192
GROUP BY addedby
) sumWorkedFinder ON AddedByFinder.AddedById = sumWorkedFinder.addedby
WHERE entrydate BETWEEN '2017-04-02' AND '2017-04-13 23:59:59'
AND ActivityId = 3192
GROUP BY AddedById,
AddedByName
ORDER BY AddedByName;
(Explanation to follow...)
If you have any questions or comments, then please feel free to post a Comment accordingly.

Related

Subtracting or Adding data based on logtime of another table

So currently I have 2 tables called listings and logs table. The listings table holds a products reference number and it's current status. So suppose if it's status was Publish currently and it's sold, the status updates to Sold. Here the refno. in this table is unique since the status can change for 1 product.
Now I have another table called Logs table, this table records all the status changes that have happened for a particular product(referenced by refno) in a particular timeframe. Suppose the Product with refno. 5 was Publish on 1st October and Sold on 2nd October, The logs table will display as:
Refno
status_from
status_to
logtime
5
Stock
Publish
2021-10-01
5
Publish
Sold
2021-10-02
This is how my tables currently look like:
Listings table:('D'=>'Draft','N'=>'Action','Y'=>'Publish')
Logs Table which I'm getting using the following statement:
SELECT refno, logtime, status_from, status_to FROM (
SELECT refno, logtime, status_from, status_to, ROW_NUMBER() OVER(PARTITION BY refno ORDER BY logtime DESC)
AS RN FROM crm_logs WHERE logtime < '2021-10-12 00:00:00' ) r
WHERE r.RN = 1 UNION SELECT refno, logtime, status_from, status_to
FROM crm_logs WHERE logtime <= '2021-10-12 00:00:00' AND logtime >= '2015-10-02 00:00:00'
ORDER BY `refno` ASC
The logs table makes a new record every status change made and passes the current timestamp as the logtime, and the listings table changes/updates the status and updates its update_date. Now to get the total listings as of today I'm using the following statement:
SELECT SUM(status_to = 'D') AS draft, SUM(status_to = 'N') AS action, SUM(status_to = 'Y') AS publish FROM `crm_listings`
And this returns all the count data for status as of the current day.
Now this is where it gets confusing for me. So suppose today the count under action is 10 and tomorrow it'll be 15, and I want to retrieve the total that was present yesterday(10). So for this what I would've to do is take todays total(15) and subtract all the places where a product was changed to draft in between yesterday and today(Total count today in listing table - count(*) where status_to='Action' from logs table). Or vice versa, if yesterday it was 10 under action and today it is 5, it should add the values from the status_from column in logs table
Note: Refno isn't unique in my logs table since a product with the same refno can be marked as publish 1 day and unpublish another, but it is unique in my listings table.
Link to dbfiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=01cb3ccfda09f6ddbbbaf02ec92ca894
I am sure it can be simplifed or better. But its my query and logic :
I found status_changes per refno's and calculated total changes from the desired day to present :
select status_logs, sum(cnt_status) to_add from (
SELECT
status_to as status_logs, -1*count(*) cnt_status
FROM logs lm
where
id = (select max(id) from logs l where l.refno = lm.refno) and
logtime >= '2021-10-01 00:00:00'
group by status_to
union all
SELECT
status_from, count(*) cnt_status_from
FROM logs lm
where
id = (select max(id) from logs l where l.refno = lm.refno) and
logtime >= '2021-10-01 00:00:00'
group by status_from ) total_changes
group by status_logs
I matched the keys between listings table and logs table by converting listings table keys :
select
case status
when 'D' THEN 'Draft'
when 'A' THEN 'Action'
when 'Y' THEN 'Publish'
when 'S' THEN 'Sold'
when 'N' THEN 'Let'
END status_l ,COUNT(*) c
from listings
group by status
I joined them and add the calculations to total sum of current data.
I had to use full outer join , so i have one left and one right join with the same subqueries.
Lastly I used distinct , since it will generate same result for each joined query and used ifnull to bring the other tables status to the other column .
select distinct IFNULL(status_l, status_logs) status, counts_at_2021_10_01
from (select l.*,
logs.*,
l.c + ifnull(logs.to_add, 0) counts_at_2021_10_01
from (select case status
when 'D' THEN
'Draft'
when 'A' THEN
'Action'
when 'Y' THEN
'Publish'
when 'S' THEN
'Sold'
when 'N' THEN
'Let'
END status_l,
COUNT(*) c
from listings
group by status) l
left join (
select status_logs, sum(cnt_status) to_add
from (SELECT status_to as status_logs,
-1 * count(*) cnt_status
FROM logs lm
where id = (select max(id)
from logs l
where l.refno = lm.refno)
and logtime >= '2021-10-01 00:00:00'
group by status_to
union all
SELECT status_from, count(*) cnt_status_from
FROM logs lm
where id = (select max(id)
from logs l
where l.refno = lm.refno)
and logtime >= '2021-10-01 00:00:00'
group by status_from) total_changes
group by status_logs) logs
on logs.status_logs = l.status_l
union all
select l.*,
logs.*,
l.c + ifnull(logs.to_add, 0) counts_at_2021_05_01
from (select case status
when 'D' THEN
'Draft'
when 'A' THEN
'Action'
when 'Y' THEN
'Publish'
when 'S' THEN
'Sold'
when 'N' THEN
'Let'
END status_l,
COUNT(*) c
from listings
group by status) l
right join (
select status_logs, sum(cnt_status) to_add
from (SELECT status_to as status_logs,
-1 * count(*) cnt_status
FROM logs lm
where id = (select max(id)
from logs l
where l.refno = lm.refno)
and logtime >= '2021-10-01 00:00:00'
group by status_to
union all
SELECT status_from, count(*) cnt_status_from
FROM logs lm
where id = (select max(id)
from logs l
where l.refno = lm.refno)
and logtime >= '2021-10-01 00:00:00'
group by status_from) total_changes
group by status_logs) logs
on logs.status_logs = l.status_l) l

I am missing an alias for a derived table

I know, this question has been asked very often but I know my error, I know how I could fix it, but I canĀ“t find the point where the error is. In my opinion, all the subqueries have different and unique names, I even gave the columns different names then the subqueries. Any help would be appreciated. Where is the point I am missing an alias?
Whenever I am trying to run this query I get the response "Every derived table must have its alias", which is an understandable error message, but I can't figure out where my error is located.
SELECT
mso.entity_id,
GROUP_CONCAT(msh.comment) AS comment,
msoa.lastname,
base_grand_total,
mso.created_at,
mso.status,
marketplace_order_id AS amazon_order_id,
clvData.recurrenceRate,
clvData.avgRepRate
FROM
mag_sales_flat_order AS mso
LEFT JOIN mag_sales_flat_order_status_history AS msh ON mso.entity_id = msh.parent_id
LEFT JOIN mag_sales_flat_order_address AS msoa ON mso.entity_id = msoa.parent_id
left join (
select
cast(((cet.cec - cnt.cnc) / cst.csc) AS decimal(6, 2)) as recurrenceRate,
avg(repRate.countedOrders) AS avgRepRate
from(
Select
*,
(
select
count(customer_email) AS csc
from
mag_sales_flat_order
where
created_at between '2017-01-01'
and '2017-12-31'
) AS cst,
(
select
count(customer_email) AS cec
from
mag_sales_flat_order
where
created_at between '2017-01-01'
and '2020-12-31'
) AS cet,
(
select
count(mso_new.customer_email) AS cnc
from
(
select
*
from
mag_sales_flat_order
where
created_at between '2018-01-01'
and current_date()
) AS mso_new
left join (
select
*
from
mag_sales_flat_order
where
created_at between '2017-01-01'
and '2017-12-31'
) AS mso_old on mso_new.customer_email = mso_old.customer_email
)) AS cnt
join (
select
customer_email,
count(grand_total) as countedOrders,
sum(grand_total) as summedOrders
from
mag_sales_flat_order
group by
customer_email
) AS repRate on cl.customer_email = repRate.customer_email
) AS clvData on mso.customer_email = clvData.customer_email
WHERE
store_id IN({$store['id']})
AND (
mso.status = 'complete'
OR mso.status = 'closed'
OR mso.status = 'processing'
OR mso.status = 'exported'
OR mso.status LIKE 'pending%'
)
AND (
DATE_FORMAT(mso.created_at, '%Y-%m-%d') >= '$begin_date'
)
AND (
DATE_FORMAT(mso.created_at, '%Y-%m-%d') <= '$end_date'
)
GROUP BY
entity_id;
SELECT
mso.entity_id,
GROUP_CONCAT(msh.comment) AS comment,
msoa.lastname,
base_grand_total,
mso.created_at,
mso.status,
marketplace_order_id AS amazon_order_id,
clvData.recurrenceRate,
clvData.avgRepRate
FROM mag_sales_flat_order AS mso
LEFT JOIN mag_sales_flat_order_status_history AS msh ON mso.entity_id = msh.parent_id
LEFT JOIN mag_sales_flat_order_address AS msoa ON mso.entity_id = msoa.parent_id
LEFT JOIN
(
SELECT cast(((cet.cec - cnt.cnc) / cst.csc) AS decimal(6, 2)) as recurrenceRate, avg(repRate.countedOrders) AS avgRepRate
FROM
(
SELECT *,
(
SELECT count(customer_email) AS csc
FROM mag_sales_flat_order
WHERE created_at BETWEEN '2017-01-01' AND '2017-12-31'
) AS cst,
(
SELECT count(customer_email) AS cec
FROM mag_sales_flat_order
WHERE created_at BETWEEN '2017-01-01' AND '2020-12-31'
) AS cet,
(
SELECT count(mso_new.customer_email) AS cnc
FROM
(
SELECT *
FROM mag_sales_flat_order
WHERE created_at BETWEEN '2018-01-01' AND getdate()
) AS mso_new
LEFT JOIN
(
SELECT *
FROM mag_sales_flat_order
WHERE created_at BETWEEN '2017-01-01' AND '2017-12-31'
) AS mso_old on mso_new.customer_email = mso_old.customer_email
) AS cnt
) as cl
JOIN
(
SELECT customer_email, count(grand_total) as countedOrders, sum(grand_total) as summedOrders
FROM mag_sales_flat_order
GROUP BY customer_email
) AS repRate on cl.customer_email = repRate.customer_email
) AS clvData on mso.customer_email = clvData.customer_email
WHERE store_id IN({ $ store ['id'] })
AND
(
mso.status = 'complete'
OR mso.status = 'closed'
OR mso.status = 'processing'
OR mso.status = 'exported'
OR mso.status LIKE 'pending%'
)
AND
(
DATE_FORMAT(mso.created_at, '%Y-%m-%d') >= '$begin_date'
)
AND
(
DATE_FORMAT(mso.created_at, '%Y-%m-%d') <= '$end_date'
)
GROUP BY entity_id;

Select in select - Every derived table must have its own alias error

I'm trying to get from database information about orders grouped by date.
I have table sales_flat_order, where I have it's id, order creation date, total_paid for order, and order item count. And I have table sales_flat_order_item where are orders items with it prices.
I created script to get order information by day:
SELECT
DATE( sales_flat_order.created_at ) AS date,
SUM( sales_flat_order.total_paid ) AS sales,
SUM( sales_flat_order.total_item_count ) AS items
FROM
sales_flat_order,
sales_flat_order_payment
WHERE
sales_flat_order.status = 'complete'
AND sales_flat_order.entity_id = sales_flat_order_payment.parent_id
AND sales_flat_order_payment.method = 'checkmo'
GROUP BY DATE( sales_flat_order.created_at )
WITH ROLLUP
I get:
DATE SALES ITEMS
2013-03-05 72 3
2013-03-06 100 5
And I have script to count median price:
SELECT
avg(t1.price) as median_val
FROM
(
SELECT
#rownum:=#rownum+1 as `row_number`,
d.price
FROM
sales_flat_order_item d,
(SELECT #rownum:=0) r
WHERE 1
ORDER BY d.price
) as t1,
(
SELECT
count(*) as total_rows
FROM
sales_flat_order_item d
WHERE 1
) as t2
WHERE 1
AND t1.row_number>=total_rows/2
and t1.row_number<=total_rows/2+1;
Now I'm trying to combine this two script to get:
DATE SALES ITEMS median_item_price
2013-03-05 72 3 19
2013-03-06 100 5 10.5
Combined script:
SELECT
DATE( sales_flat_order.created_at ) AS date,
SUM( sales_flat_order.total_paid ) AS sales,
SUM( sales_flat_order.total_item_count ) AS items,
sales_flat_order_item.price as median_item_price
FROM
sales_flat_order,
sales_flat_order_payment,
(
SELECT
avg(t1.price) as median_val
FROM
(
SELECT
#rownum:=#rownum+1 as `row_number`,
d.price
FROM
sales_flat_order_item d,
(SELECT #rownum:=0) r
WHERE 1
ORDER BY d.price
) as t1,
(
SELECT
count(*) as total_rows
FROM
sales_flat_order_item d
WHERE 1
) as t2
WHERE 1
AND t1.row_number>=total_rows/2
and t1.row_number<=total_rows/2+1
) as sales_flat_order_item
WHERE
sales_flat_order.status = 'complete'
AND sales_flat_order.entity_id = sales_flat_order_payment.parent_id
AND sales_flat_order_payment.method = 'checkmo'
AND DATE(sales_flat_order_item.created_at) = DATE(sales_flat_order.created_at)
GROUP BY DATE( sales_flat_order.created_at )
WITH ROLLUP
and get error: #1248 - Every derived table must have its own alias
here is database: http://sqlfiddle.com/#!2/7dfec
Can anyone help?
Solution:
SELECT
DATE( sales_flat_order.created_at ) AS date,
SUM( sales_flat_order.total_paid ) AS sales,
SUM( sales_flat_order.total_item_count ) AS items,
MAX( median.median_val ) as median_item_price
FROM
sales_flat_order,
sales_flat_order_payment,
(
SELECT DATE(sq.created_at) as median_date, avg(sq.price) as median_val FROM (
SELECT t1.row_number, t1.price, t1.created_at FROM(
SELECT IF(#prev!=d.created_at, #rownum:=1, #rownum:=#rownum+1) as `row_number`, d.price, #prev:=d.created_at AS created_at
FROM sales_flat_order_item d, (SELECT #rownum:=0, #prev:=NULL) r
ORDER BY d.price
) as t1 INNER JOIN
(
SELECT count(*) as total_rows, created_at
FROM sales_flat_order_item d
GROUP BY created_at
) as t2
ON t1.created_at = t2.created_at
WHERE 1=1
AND t1.row_number>=t2.total_rows/2 and t1.row_number<=t2.total_rows/2+1
)sq
group by DATE(sq.created_at)
) as median
WHERE
sales_flat_order.status = 'complete'
AND sales_flat_order.entity_id = sales_flat_order_payment.parent_id
AND sales_flat_order_payment.method = 'checkmo'
AND median.median_date = DATE( sales_flat_order.created_at )
GROUP BY DATE( sales_flat_order.created_at )
WITH ROLLUP

How to merge the result of this 2 queries in mysql server

I am actually stuck in merging the result of this two queries:
first query:
SELECT c.code, c.name, pc.sku, pc.cat_code, pp.title
FROM `cat_parent` cp, cat c, prod_cat pc, products pp
WHERE c.code = cp.cat_code
AND cp.cat_code = pc.cat_code
AND pp.sku = pc.sku
AND cp.parent_code = 01110
AND hide =0
The result I get is:
Second query:
SELECT `sku` , `update_date` , `description` , count( * ) AS total_sold
FROM `orderline`
WHERE `update_date` >= ( DATE_ADD(CURDATE( ) , INTERVAL -14 DAY ) )
AND `update_date` <= ( DATE_ADD(CURDATE( ) , INTERVAL -7 DAY ) )
GROUP BY left( sku, 7 )
ORDER BY total_sold DESC
The result:
The question I want to ask that how can I get the result by filtering the sku available in both tables.
Just bit confused on that part....any ideas will be appreciated.
This is only part of the data. there is heaps of data. Yes, I want to merge the both tables and want to find the common sku available in both tables.
My expected result will be sku, title, total sold.
Thanks, anyway I managed to get around to get the result.
My final query:
SELECT * FROM (
SELECT sku , update_date , description FROM orderline WHERE
update_date >= '2012-03-06' AND update_date <= '2012-03-07' )g
JOIN (
SELECT c.code, c.name, pc.sku, pc.cat_code FROM cat_parent cp, cat
c, prod_cat pc, products pp WHERE c.code = cp.cat_code AND cp.cat_code
= pc.cat_code AND pp.sku = pc.sku AND cp.parent_code =01110 AND hide =0 )p ON left( g.sku, 7 ) = left( p.sku, 7 )
Something like this -
SELECT
`c`.`code`, `c`.`name`, `pc`.`sku`, `pc`.`cat_code`, `pp.title`,
`ol`.`sku`, `ol`.`update_date`, `ol`.`description`, COUNT(*) AS `total_sold`
FROM `cat_parent` `cp`
INNER JOIN `cat` `c`
ON `c`.`code` = `cp`.`cat_code`
INNER JOIN `prod_cat` `pc`
ON `cp`.`cat_code` = `pc`.`cat_code`
INNER JOIN `products` `pp`
ON `pp`.`sku` = `pc`.`sku`
INNER JOIN `orderline` `ol`
ON LEFT(`pc`.`sku`, 7) = LEFT(`ol`.`sku`, 7)
WHERE `cp`.`parent_code` = 01110
AND `hide` = 0
AND `ol`.`update_date` >= ( DATE_ADD(CURDATE( ) , INTERVAL -14 DAY ) )
AND `ol`.`update_date` <= ( DATE_ADD(CURDATE( ) , INTERVAL -7 DAY ) )
GROUP BY left( `ol`.`sku`, 7 )
ORDER BY `total_sold` DESC

Percentages in MySQL

Using this query,
SELECT company, YEAR( date ) as year, COUNT( * ) as total
FROM table
WHERE company = "Medtronic"
OR company = "Private"
GROUP BY YEAR( date )
I get a table like this:
Company year total
Medtronic 1998 6
Private 1998 5
Medtronic 1999 5
Private 1999 1
How do I calculate the % that is contributed by each company for each year?
For example, the percentage contributed by Medtronic in year 1998 is
6 / (6+5) = 54.5%
I have been trying to make a MySQL query to calculate the percentages.
Thanks guys.
Use:
SELECT x.company,
x.year,
x.annual_total
x.annual_total / y.total AS percentage
FROM (SELECT t.company,
YEAR(t.date) as year,
COUNT( * ) as annual_total
FROM TABLE t
WHERE t.company IN ('Medtronic', 'Private')
GROUP BY YEAR( t.date ) ) x
JOIN (SELECT t.company,
COUNT(*) 'total'
FROM TABLE t
WHERE t.company IN ('Medtronic', 'Private')
GROUP BY t.company) y ON y.company = x.company
If you want the percentage with particular decimal places, use:
CAST(x.annual_total / y.total AS DECIMAL(2,2)) AS percentage
Check that this gives the count per company you expect:
SELECT t.company,
COUNT(*) 'total'
FROM TABLE t
WHERE t.company IN ('Medtronic', 'Private')
GROUP BY t.company
My SQL query:
SELECT x.company, x.year, x.annual_total, CAST( x.annual_total / y.total AS DECIMAL( 2, 2 ) ) AS percentage
FROM (
SELECT t.company, YEAR( t.date ) AS year, COUNT( * ) AS annual_total
FROM my_patents AS t
WHERE t.company = 'Private'
GROUP BY YEAR( t.date )
)x
JOIN (
SELECT t.company, COUNT( * ) AS total
FROM my_patents AS t
WHERE t.company = 'Medtronic'
OR t.company = 'Private'
GROUP BY t.company
)y ON y.company = x.company
my results:
Private 1998 5 0.04
when i run this query:
SELECT t.company, YEAR( date ) , COUNT( * ) AS total
FROM my_patents AS t
WHERE t.company = 'Medtronic'
OR t.company = 'Private'
GROUP BY t.company, YEAR( date )
I get
Medtronic 1998 6
Private 1998 5