I have the following database ( with many more rows ):
There are dates and times for which I might have just Temperature, or x-Axis Vibration, or any field. Some timestamps (like the ones in this pic) have missing fields like Z-Axis Vibration
I want to fetch all this data in the following format and convert fields which are not found to 'NA'
I have tried the following query:
select entry_date, entry_time, field_name, ifnull(value, "NA") as value
from tablename
where group_name = "SL1-DSM-1" and
concat(entry_date, " ", entry_time) in
( select distinct(concat(entry_date, " ", entry_time))
from tablename
where timestamp(entry_date, entry_time) between "2019-07-22 00:00:00" and
"2019-07-23 00:00:00" ) and
field_name in (select distinct(field_name) from tablename where group_name =
"SL1-DSM-1");
This is giving me the result:
Is there a way this can be achieved using a single query ? Or in minimum no. of queries so as to make it faster.
NOTE: Currently, I'm using different queries for each group and field, and compiling them into a common format, but I wanted if this could be returned my MySQL itself
You can generate all the rows using cross join and then fill in the missing values. 'N/A' is not a good fill in, because it is a string. Just use NULL.
Something like this:
select entry_date, entry_time, group_name, field_name,
t.value
from (select distinct entry_date, entry_time, group_name
from tablename
) dtg cross join
(select distinct field_name
from tablename
) f left join
tablename t
using (entry_date, entry_time, group_name, field_name)
Related
I got a field "type" which is either "member" or "casual". I got
another categorical field called "duration_type".
And I want to calculate the percentage of each categories in the duration_type, separately for members and casual users.
So I run two separate scripts where their only difference is the WHERE type = "member" becomes WHERE type = "casual" .
SELECT
type,
duration_type,
CONCAT(ROUND((COUNT(*)/ (SELECT COUNT(*) FROM temp WHERE type ="member")*100 ),2),"%") AS per
FROM temp
WHERE type = "member"
GROUP BY duration_type;
SELECT
type,
duration_type,
CONCAT(ROUND((COUNT(*)/ (SELECT COUNT(*) FROM temp WHERE type ="casual")*100 ),2),"%") AS per
FROM temp
WHERE type = "casual"
GROUP BY duration_type;
Is there a more compact way to do this in only one command? Simply using GROUP BY type, duration_type is not correct.
You should group by type, duration_type and use SUM() window function to get the total number of rows for each type:
SELECT type, duration_type,
CONCAT(ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (PARTITION BY type), 2), '%') AS per
FROM temp
GROUP BY type, duration_type;
Or, if your version of MySql does not support window functions:
SELECT t1.type, t1.duration_type,
CONCAT(ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM temp t2 WHERE t2.type = t1.type), 2), '%') AS per
FROM temp t1
GROUP BY t1.type, t1.duration_type;
See a simplified demo.
I have a table
and I'm trying to write a select statement with ifnull condition for same type value like to get the result as shown in this table
Below is the sql I have tried -
SELECT
type,
memo,
IFNULL( memo, type = type) memo_all,
amount
FROM
table
But I get the same result as memo column in memo_all column with above query as can be seen in this table 3. Please find the sqlfiddle here with above query and table - http://sqlfiddle.com/#!9/55c43f
What am I missing here? Is there any alternative way to get the result as shown in table 2?
Just in case you are using a version of MySQL earlier than 8+, here is an alternative to Gordon's answer which doesn't use window functions:
SELECT
t1.type,
t1.memo,
t2.memo AS memo_all,
t1.amount
FROM yourTable t1
INNER JOIN
(
SELECT type, MAX(memo) AS memo
FROM yourTable
GROUP BY type
) t2
ON t1.type = t2.type;
SELECT t1.*, t2.memo memo_all
FROM `table` t1
JOIN `table` t2 USING (type)
WHERE t2.memo != '';
Solution which uses one source table copy:
SELECT `table`.*, #tmp := CASE WHEN memo = '' THEN #tmp ELSE memo END memo_all
FROM `table`, (SELECT #tmp := '') variable
ORDER BY type, memo DESC;
Use window functions:
SELECT type, memo,
max(memo) over (partition by type) as memo_all
amount
FROM table;
You want to "borrow" the value from another row. A simple scalar function is not going to do that. However, window functions provide this capability.
EDIT:
In older versions of MySQL, you can use a correlated subquery:
SELECT type, memo,
COALESCE(memo,
(SELECT t2.memo
FROM table t2
WHERE t2.type = t.type AND t2.memo IS NOT NULL
LIMIT 1
)
) as memo_all
amount
FROM table t;
I am trying to group single user data which is spread in multiple row in mySQL.
I have tried using group by, Joining multiple times all 4 column but not able to achieve.
Below is my Table and Schema
and I Am trying to get it in the below form as Result
Can you please help me to form a query in MYSQL
Join to the table all the max columns you get after grouping by deviceid:
select distinct
t.date,
t.deviceid,
g.country,
g.affid,
g.accountid,
g.package
from tablename inner join (
select
deviceid,
max(country) country,
max(affid) affid,
max(accountid) accountid,
max(package) package
from tablename
group by deviceid
) g on g.deviceid = t.deviceid
You can do aggregation :
select deviceid, max(country), max(affid), max(accountid), max(package)
from table t
group by deviceid;
EDIT : If you are working with higher version then you can use window function :
select distinct t.Date, t.deviceid,
max(t.country) over (partition by t.deviceid) as country,
max(t.affid) over (partition by t.deviceid) as deviceid,
. . .
from table t;
I have the following table:
CREATE TABLE sometable (my_id INTEGER PRIMARY KEY AUTOINCREMENT, name STRING, number STRING);
Running this query:
SELECT * FROM sometable;
Produces the following output:
1|someone|111
2|someone|222
3|monster|333
Along with these three fields I would also like to include a count representing the amount of times the same name exists in the table.
I've obviously tried:
SELECT my_id, name, count(name) FROM sometable GROUP BY name;
though that will not give me an individual result row for every record.
Ideally I would have the following output:
1|someone|111|2
2|someone|222|2
3|monster|333|1
Where the 4th column represents the amount of time this number exists.
Thanks for any help.
You can do this with a correlated subquery in the select clause:
Select st.*,
(SELECT count(*) from sometable st2 where st.name = st2.name) as NameCount
from sometable st;
You can also write this as a join to an aggregated subquery:
select st.*, stn.NameCount
from sometable st join
(select name, count(*) as NameCount
from sometable
group by name
) stn
on st.name = stn.name;
EDIT:
As for performance, the best way to find out is to try both and time them. The correlated subquery will work best when there is an index on sometable(name). Although aggregation is reputed to be slow in MySQL, sometimes this type of query gets surprisingly good results. The best answer is to test.
Select *, (SELECT count(my_id) from sometable) as total from sometable
I have read many replies and to similar questions but cannot seem to apply it to my situation. I have a table that averages 10,000 records and is ever changing. It containing a column called deviceID which has about 20 unique values, another called dateAndTime and many others including status1 and status2. I need to isolate one instance each deviceID, showing the record that had the most current dateAndTime. This works great using:
select DISTINCT deviceID, MAX(dateAndTime)
from MyTable
Group By deviceID
ORDER BY MAX(dateAndTime) DESC
(I have noticed omitting DISTINCT from the above statement also yields the same result)
However, I cannot expand this statement to include the fields status fields without incurring errors in the statement or incorrect results. I have tried using IN and EXISTS and syntax to isolate rows, all without luck. I am wondering how I can nest or re-write this query so that the results will display the unique deviceID's, the date of the most recent record and the corresponding status fields associated with those unique records.
If you can guarantee that the DeviceID + DateAndTime is UNIQUE you can do the following:
SELECT *
FROM
MyTable as T1,
(SELECT DeviceID, max(DateAndTime) as mx FROM MyTable group by DeviceID) as T2
WHERE
T1.DeviceID = T2.DeviceID AND
T1.DateAndTime = T2.mx
So basically what happens is, that you do a group by on the DeviceID (NOTE: A GROUP BY always goes with an aggregate function. We are using MAX in this case).
Then you join the Query with the Table, and add the DeviceID + DateAndTime in the WHERE clause.
Side Note... GROUP BY will return distinct elements with or without adding DISTINCT because all rows are distinct by default.
Maybe:
SELECT a.*
FROM( SELECT DISTINCT *,
ROW_NUMBER() OVER (PARTITION BY deviceID ORDER BY dateAndTime DESC) as rown
FROM MyTable ) a
WHERE a.rown = 1