MySQL error 1351 Can't Create a View - mysql

Below is a query that I'm trying to create a view with. When I run it, "I get Error Code: 1351. View's SELECT contains a variable or parameter". WHy is this the case and is there a way around this that I can create a view without changing too much of what I have in my current query?
Thanks!!
create view delta as
select rnk2.`date`,
case when rnk1.r1=1 and rnk2.r2=1 then rnk1.X else rnk2.X-rnk1.X end as 'Daily Total'
from (
select `date`,X,#r1:=#r1+1 as r1
from samples, (select #r1:=0) a
order by `date` ) rnk1
inner join
(select `date`,X,#r2:=#r2+1 as r2
from samples, (select #r2:=0) b
order by `date`) rnk2
on (rnk1.r1=1 and rnk2.r2=1) or (rnk1.r1+1=rnk2.r2)
order by rnk2.`date`;

mySQL views does not allow user variables nor subqueries, so I changed the query and split the view into two parts.
The first view will assign a row number on the table SAMPLE according to date. Then the 2nd view will make use of the first view (sample_vw) to do the main query.
create view sample_vw as
select a.`date`, a.X, count(*) as rn
FROM samples a
JOIN samples b
ON a.`date` >= b.`date`
GROUP BY a.`date`;
create view delta as
SELECT t1.`date`,
case when t1.rn=1 and t2.rn=1 then t1.X else t2.X-t1.X end as 'Daily Total'
FROM sample_vw t1
INNER JOIN sample_vw t2
ON t1.rn+1=t2.rn or (t1.rn=1 and t2.rn=1);

Related

Using the results of a function multiple times for duplicates - SQL

I am trying to produce a result that shows duplicates in a table. One method I found for getting duplicates and showing them is to run the select statement again through an inner join. However, one of my columns needs to be the result of a function, and the only thing I can think to do is use an alias, however I can't use the alias twice in a SELECT statement.
I am not sure what the best way to run this code for getting the duplicates I need.
My code below
SELECT EXTRACT(YEAR_MONTH FROM date) as 'ndate', a.transponderID
FROM dispondo_prod_disposition.event a
inner JOIN (SELECT EXTRACT(YEAR_MONTH FROM date) as ???,
transponderID, COUNT(*)
FROM dispondo_prod_disposition.event
GROUP BY mdate, transponderID
HAVING count(*) > 1 ) b
ON ndate = ???
AND a.transponderID = b.transponderID
ORDER BY b.transponderID
SELECT b.ndate, transponderID
FROM dispondo_prod_disposition.event a
INNER JOIN ( SELECT EXTRACT(YEAR_MONTH FROM date) as ndate,
transponderID
FROM dispondo_prod_disposition.event
GROUP BY 1, 2
HAVING COUNT(*) > 1 ) b USING (transponderID)
WHERE b.ndate = ??? -- for example, WHERE b.ndate = 202201
ORDER BY transponderID

using an aggregate value along with non-agrregate values in SQL

I need to use the average value of the column 'sales' from a table called 'previous_target' and compare that value with the individual rows of the same column 'sales' of the same table .
I get the required result when I disable the SQL mode from only_full_group_by.
But i would like to know if there is a better way to write the code without disabling the full group by mode.
Here is an example SQL query.
select
f.id,t.sale as previous_target,
case
when t.sale > 1.25*(avg(t.sale)) then round((avg(t.sale)*1.1),2)
when t.sale < 0.9*(avg(t.sale)) then round((avg(t.sale)*0.9),2)
else
t.sale
end
as current_target from
details f
inner join prev_target t on f.l_number=t.l_number
inner join time_details ft on ft.id=f.id
note:if i add the line
group by f.id,f.l_number,t.sale
it just copies the same value onto the current_target column .
can anyone suggest a way to use the average of the sales column from the prev_target table and compare it with each row of the same table with the given conditions.
I hope I conveyed my requirement without causing much confusion.
SELECT f.id, t.sale AS previous_target,
CASE
WHEN t.sale > 1.25*(a.sale) then round(((a.sale)*1.1),2)
WHEN t.sale < 0.9*(a.sale) then round(((a.sale)*0.9),2)
ELSE
t.sale
END AS current_target
FROM details f
INNER JOIN prev_target t ON f.l_number = t.l_number
INNER JOIN
(
SELECT avg(t.sale) AS sale, t.l_number FROM prev_target t GROUP BY t.l_number
)AS a ON t.l_number = a.l_number
INNER JOIN time_details ft ON ft.id = f.id
Using OVER clause would be best recommended here for aggregation. I have created sample run for you (ofcourse different data and columns) but you will get the gist.
create table sales(amount int);
insert into sales values(5);
insert into sales values(10);
insert into sales values(15);
insert into sales values(20);
insert into sales values(10);
select * from sales;
select avg(amount) average from sales;
select amount, case when amount >= (avg(amount) over (PARTITION BY 1)) then 'Good' else 'Bad' end as type from sales;
Result >>

MySQL chooses to execute queries, or not, at whim

For a reporting output, I used to DROP and recreate a table 'mis.pr_approval_time'. but now I just TRUNCATE it.
After populating the above table with data, I run an UPDATE statement, but I have written that as a SELECT below...
SELECT t.account_id FROM mis.hj_approval_survey h INNER JOIN mis.pr_approval_time t ON h.country = t.country AND t.scheduled_at =
(
SELECT MAX(scheduled_at) FROM mis.pr_approval_time
WHERE country = h.country
AND scheduled_at <= h.created_at
AND TIME_TO_SEC(TIMEDIFF(h.created_at, scheduled_at)) < 91
);
When I run the above statement or even just...
SELECT t.account_id FROM mis.hj_approval_survey h INNER JOIN mis.pr_approval_time t ON h.country = t.country AND t.scheduled_at =
(
SELECT MAX(scheduled_at) FROM mis.pr_approval_time
WHERE country = h.country
);
...it runs forever and does not seem to finish. There are only ~3,400 rows in hj_approval_survey table and 29,000 rows in pr_approval_time. I run this on an Amazon AWS instance with 15+ GB RAM.
Now, if I simply right click on pr_approval_time table and choose ALTER TABLE option, and just close without doing anything, then the above queries run within seconds.
I guess when I trigger the ALTER TABLE option and Workbench populates the table fields, it probably improves its execution plan somehow, but I am not sure why. Has anyone faced anything similar to this? How can I trigger a better execution plan check without right clicking the table and choosing 'ALTER TABLE'
EDIT
It may be noteworthy to mention that my organisation also uses DOMO. Originally, I had this setup as an MySQL Dataflow on DOMO, but the query would not complete on most occassions, but I have observed it finish at times.
This was the reason why I moved this query back to our AWS MySQL RDS. So the problem has not only been observed on our own MySQL RDS, but probably also on DOMO
I suspect this is slow because of the correlated subquery (subquery depends on row values from parent table, meaning it has to execute for each row). I'd try and rework the pr_approval_time table slightly so it's point-in-time and then you can use the JOIN to pick the correct rows without doing a correlated subquery. Something like:
SELECT
hj_approval_survey.country
, hj_approval_survey.created_at
, pr_approval_time.account_id
FROM
#hj_approval_survey AS hj_approval_survey
JOIN (
SELECT
current_row.country
, current_row.scheduled_at AS scheduled_at_start
, COALESCE( MIN( next_row.scheduled_at ), GETDATE() ) AS scheduled_at_end
FROM
#pr_approval_time AS current_row
LEFT OUTER JOIN
#pr_approval_time AS next_row ON (
next_row.country = current_row.country
AND next_row.scheduled_at > current_row.scheduled_at
)
GROUP BY
current_row.country
, current_row.scheduled_at
) AS pr_approval_pit ON (
pr_approval_pit.country = hj_approval_survey.country
AND ( hj_approval_survey.created_at >= pr_approval_pit.scheduled_at_start
AND hj_approval_survey.created_at < pr_approval_pit.scheduled_at_end
)
)
JOIN #pr_approval_time AS pr_approval_time ON (
pr_approval_time.country = pr_approval_pit.country
AND pr_approval_time.scheduled_at = pr_approval_pit.scheduled_at_start
)
WHERE
TIME_TO_SEC( TIMEDIFF( hj_approval_survey.created_at, pr_approval_time.scheduled_at ) ) < 91
Assuming you have proper index on the columns involved in join
You could try refactoring your query using a grouped by subquery and join on country
SELECT t.account_id
FROM mis.hj_approval_survey h
INNER JOIN mis.pr_approval_time t ON h.country = t.country
INNER JOIN (
SELECT country, MAX(scheduled_at) max_sched
FROM mis.pr_approval_time
group by country
) z on z.contry = t.country and t.scheduled_at = z.max_sched

Limiting selected rows in SQL Server

In the query below I want to retrieve #MaximumRecords rows, so that no ProjectId will have rows left out beyond #MaximumRecords.
For example if #MaximumRecords=100, and ProjectId=7 has records at rows number 99-102, I wish to retrieve only rows with ProjectId=1 to ProjectId=6 (The query will run again later starting at ProjectId=7). How do I do that?
SELECT TOP (#MaximumRecords)
t1.ProjectId,
t1.Row2,
t2.Row3
FROM Table1 t1
JOIN Table2 t2 ON t1.ProjectId = t2.ProjectId
ORDER BY
t1.ProjectId ASC
WHERE
t1.ProjectId > #InitialProjectId
I worked up a solution using the Sales.SalesOrderHeader and Sales.SalesOrderDetail tables in the AdventureWorks2008R2 database using the technique to get a running total described here.
The basic idea is to get the running total of the count for each SalesOrderID (ProjectID in your case) and then select all of the data for each SalesOrderID where the running total of the count is less than #MaximumRecords. You would then need to capture the maximum ID in the data returned and use that value in the next run of your query.
This task gets a little easier with SQL Server 2012 which is also described in the link given above.
Here it is...
USE AdventureWorks2008R2
IF OBJECT_ID('tempdb..#Test', 'U') IS NOT NULL DROP TABLE #Test;
DECLARE #MaximumRecords INT
DECLARE #InitialSalesOrderID INT
SET #MaximumRecords = 500
SET #InitialSalesOrderID = 43663
SELECT a.SalesOrderID, COUNT(*) AS 'Count'
INTO #Test
FROM Sales.SalesOrderHeader a
INNER JOIN Sales.SalesOrderDetail b ON a.SalesOrderID = b.SalesOrderID
WHERE a.SalesOrderID > #InitialSalesOrderID
GROUP BY a.SalesOrderID
SELECT * FROM Sales.SalesOrderHeader a
INNER JOIN Sales.SalesOrderDetail b ON a.SalesOrderID = b.SalesOrderID
WHERE a.SalesOrderID IN (
SELECT
a.SalesOrderID
FROM
#Test a
WHERE (
SELECT
SUM(Count)
FROM
#Test b
WHERE
b.SalesOrderID <= a.SalesOrderID
) < #MaximumRecords
)
Noel

MySQL MAX(datetime) not working

I am trying to retrieve the max(date_entered) for a group of computer_ids.
The first query won't return accurate results. The second query gives me accurate results but essentially hangs unless I filter by a specific computer_id.
I'd rather use this first query
SELECT *, max(reports.date_entered)
FROM reports, hardware_reports
WHERE reports.report_id=hardware_reports.report_id
GROUP BY computer_id;
than this second query
SELECT *
FROM reports a
JOIN hardware_reports
ON a.report_id=hardware_reports.report_id
AND a.date_entered = (
SELECT MAX(date_entered)
FROM reports AS b
WHERE a.computer_id = b.computer_id)
and computer_id = 1648;
I need to either optimize second or get max to work in first.
You can alternative join it on a subquery that gets the latest record for every computer_ID.
SELECT a.*, c.*
FROM reports a
INNER JOIN
(
SELECT computer_ID, MAX(date_entered) date_entered
FROM reports
GROUP BY computer_ID
) b ON a.computer_ID = b.computer_ID
AND a.date_entered = b.date_entered
INNER JOIN hardware_reports c
ON a.report_id = c.report_id
To make it more efficient, provide an index on columns:
ALTER TABLE reports INDEX idx_report_compDate (computer_ID, date_entered)