can i use column alias in many positions in the query? - mysql

if i managed to make the folowing view in mysql
select id,name,score,total,CALCIT(total - score) as x,(CALCIT(total - score) / total) as per from tblx;
the process CALCIT(total - score) is being caculated two times
how to do some thing like this:
select id,name,score,total,CALCIT(total - score) as `x`,`x`/total as per from tblx;
where CALCIT is a function

MySQL will permit you to use a column alias inside the ORDER BY, GROUP BY clauses, but you won't be able to reuse the alias in the SELECT list. If you really needed to do this, having many instances of the calculated value, you can do a self JOIN which produces the calculation.
SELECT
id,
name,
score,
total,
x,
x / total AS per
FROM tblx JOIN (
/* Subquery JOIN which performs the calculation */
SELECT CALCIT(total - score) AS x FROM tblx xcalc
) ON tblx.id = xcalc.id
This method may be more performant than redoing the calculation in one SELECT, but as with anything, benchmark to find out.

Try something like this:
select *, x/total from (
select id,name,score,total,CALCIT(total - score) as x from tblx;
) as tblx

better you can use inner query --
select id,
name,
score,
total,
X,
X/total as per
from (
select id,
name,
score,
total,
CALCIT(total - score) as X from tblx
)

Related

Merge two select statement without ordering

There is a table TableX (id, user_id, sticky_date, created_at)
Few of them entries having sticky dates.
I am trying to get the result as,
result will contain, all the entries having sticky_date order desc and then all remaining entries order by created_at.
I tried with following query,
(SELECT * FROM TableX ORDER BY sticky_expiry_date)
UNION
( select * from TableX order by created_at desc)
But after union created_at is not working as expected. Is there any way to do this stuff in single query.
We can do this using computed columns:
SELECT *
FROM
(
SELECT *, 0 AS position, UNIX_TIMESTAMP(sticky_expiry_date) AS odr
FROM TableX
UNION -- UNION ALL ?
SELECT *, 1, -UNIX_TIMESTAMP(created_at)
FROM TableX
) t
ORDER BY
position, odr;
The idea here is that the position alias keeps track of which half of the union should come first. Then, the odr alias tracks the ordering within each half of the union. The top half uses sticky_expiry_date for the odr alias, while the second half uses created_at. To deal with the issue of ascending/descending date ordering, we can wrap the date columns in UNIX_TIMESTAMP and order by that quantity (ascending), or by that quantity negated (descending).

Simple Percentage Column in SQL

I am relatively new to SQL and looking to pick up a few simple tricks. I have managed to create a query that selects each different type of car permit (chargeType), counts the number issued for each one (num), and adds a column that shows the total number of permits issued (total). The code is below.
SELECT chargeType,
COUNT(chargeType) AS num,
(SELECT COUNT(chargeType)
FROM permit) AS total
FROM permit
GROUP BY chargeType
I now want to add a final column which shows the percentage of each permit type issued. So the number of each permit type divided by the total multiplied by 100, but I am struggling to do it. Can anybody help?
Try something like this
SELECT chargeType,
num,
total,
num / NULLIF(total, 0) * 100 AS Percenatge
FROM (SELECT chargeType,
Count(chargeType) AS num,
(SELECT Count(chargeType)
FROM permit) AS total
FROM permit
GROUP BY chargeType) a
NULLIF is used to avoid divide by zero expection
This will work. The plus of this solution is there is no subquery in SELECT
SELECT *, (num * 100 / total) as percentage
FROM
(
SELECT
chargeType,
COUNT(chargeType) AS num,
total,
(num * 100 / total) as percentage
FROM
(SELECT COUNT(chargeType) as total FROM permit) ttotal
CROSS JOIN
permit
GROUP BY
chargeType
) tsub

how to count total record using Union All in mysql

select count(*) from ((select count(*) from employee )
union ALL (select count(*) from events)) as total
this is my query i am trying to find ttoal record by given two query
this query
`select count(*) from employee`
give 300 record and
select count(*) from events
this give 100 when i try to count total record then it give always 2 record can any one tell me how to count total record by give query
You can just add together the two counts directly, no need for a UNION query:
SELECT (SELECT COUNT(*) FROM employee) + (SELECT COUNT(*) FROM events) AS total
Note that this will work because you used UNION ALL, which retains all the records in each side of the query. If you wanted to use a UNION then it would look like this:
SELECT COUNT(*) AS total
FROM
(
SELECT * FROM employee
UNION ALL
SELECT * FROM events
) t
But this would only work if the two tables have the same number (and ideally types) of columns. I would probably go with the first option in any case.
select
count(*) result.union_total
from (
(select 1 from table1)
union all
(select 1 from table2)
) result
Use this command:
SELECT
COUNT(*) AS total
FROM
(SELECT * FROM db_domains where id=695
UNION ALL
SELECT * FROM db_domains where id=694
) AS A;
Result: total: 2 ( According my sql table )
Be sure that:
1.The used SELECT statements have a same number of columns.
Otherwise you will get this error:
Error Code: 1222. The used SELECT statements have a different number of columns
2.Every derived table must have its own alias.
Otherwise you will get this error :
Error Code: 1248. Every derived table must have its own alias
See the snapshot in MYSQL Workbench. ( I have tested on workbench ):
In The last snapshot: You can see the result is: 1106

invalid use of group function error for extracting date with max and min

I'm trying to execute a query like this:
SELECT MAX(counter), MIN(counter) ,
my_date IN (SELECT my_date FROM my_table WHERE counter = MAX(counter) ) AS max_Date ,
my_date IN (SELECT my_date FROM my_table WHERE counter = MIN(counter) ) AS min_Date
FROM my_table;
and it's giving me the "invalid use of group function" error. what I want to do is to find the date for the maximum counter and then find the date for the minimum counter. Any help!! really appreciate it .. thanks.
You're trying to use the result of aggregate functions (max()/min()) on a row-by-row basis, but those results are not available until the DB has scanned the entire table.
e.g. it's a chicken and egg problem. You need to count chickens, but the eggs that will produce the chickens haven't even been layed yet.
That's why there's HAVING clauses, which allow you to use the results of aggregate functions to do filtering.
Try this for the subqueries:
SELECT my_date FROM my_table HAVING counter = MIN(counter)
^^^^^^
You can get the dates where the largest and smallest counter values appear using a trick with group_concat() and substring_index():
SELECT MAX(counter), MIN(counter) ,
substring_index(group_concat(my_date order by counter desc), ',', 1) as max_date,
substring_index(group_concat(my_date order by counter), ',', 1) as min_date
FROM my_table;
Note: You probably want to format the date first to your liking.
You can also do this with a join.
The problem with your query is:
where counter = min(counter)
You can't include aggregation functions in the where clause, because both are referring to the table in the subquery. You could possibly do this using aliaes, but why bother? There are other ways to write the query.
You need a subselect to get the max and min counters and then join back against the table a couple of times to get the other values from those rows.
SELECT MaxCounter, MinCounter, a.my_date, b.my_date
FROM (SELECT MAX(counter) AS MaxCounter, MIN(counter) AS MinCounter
FROM my_table) Sub1
INNER JOIN my_table a ON Sub1.MaxCounter
INNER JOIN my_table b ON Sub1.MinCounter
Note that this does assume that counter is unique!

SQL Work out the average time difference between total rows

I've searched around SO and can't seem to find a question with an answer that works fine for me. I have a table with almost 2 million rows in, and each row has a MySQL Date formatted field.
I'd like to work out (in seconds) how often a row was inserted, so work out the average difference between the dates of all the rows with a SQL query.
Any ideas?
-- EDIT --
Here's what my table looks like
id, name, date (datetime), age, gender
If you want to know how often (on average) a row was inserted, I don't think you need to calculate all the differences. You only need to sum up the differences between adjacent rows (adjacent based on the timestamp) and divide the result by the number of the summands.
The formula
((T1-T0) + (T2-T1) + … + (TN-TN-1)) / N
can obviously be simplified to merely
(TN-T0) / N
So, the query would be something like this:
SELECT TIMESTAMPDIFF(SECOND, MIN(date), MAX(date)) / (COUNT(*) - 1)
FROM atable
Make sure the number of rows is more than 1, or you'll get the Division By Zero error. Still, if you like, you can prevent the error with a simple trick:
SELECT
IFNULL(TIMESTAMPDIFF(SECOND, MIN(date), MAX(date)) / NULLIF(COUNT(*) - 1, 0), 0)
FROM atable
Now you can safely run the query against a table with a single row.
Give this a shot:
select AVG(theDelay) from (
select TIMESTAMPDIFF(SECOND,a.date, b.date) as theDelay
from myTable a
join myTable b on b.date = (select MIN(x.date)
from myTable x
where x.date > a.date)
) p
The inner query joins each row with the next row (by date) and returns the number of seconds between them. That query is then encapsulated and is queried for the average number of seconds.
EDIT: If your ID column is auto-incrementing and they are in date order, you can speed it up a bit by joining to the next ID row rather than the MIN next date.
select AVG(theDelay) from (
select TIMESTAMPDIFF(SECOND,a.date, b.date) as theDelay
from myTable a
join myTable b on b.date = (select MIN(x.id)
from myTable x
where x.id > a.id)
) p
EDIT2: As brilliantly commented by Mikael Eriksson, you may be able to just do:
select (TIMESTAMPDIFF(SECOND,(MAX(date),MIN(date)) / COUNT(*)) from myTable
There's a lot you can do with this to eliminate off-peak hours or big spans without a new record, using the join syntax in my first example.
Try this:
select avg(diff) as AverageSecondsBetweenDates
from (
select TIMESTAMPDIFF(SECOND, t1.MyDate, min(t2.MyDate)) as diff
from MyTable t1
inner join MyTable t2 on t2.MyDate > t1.MyDate
group by t1.MyDate
) a