MySql query ordering in JOIN tables - mysql

Good day every one
I have three MySql tables
-Doc
-DocType
-Org
I made a query like that:
Select Doc.Code,Doc.DataAccept,DocTypes.Name,Org.Name
From
Doc,DocTypes,Org
Where Doc.Type=DocTypes.Code AND Doc.Org=Org.Code AND Doc.Code;
in Result i have
|Code|DataAccept|Name|Name|
17 | - | - | - |
18 | - | - | - |
24 | - | - | - |
26 | - | - | - |
32 | - | - | - |
the Code field is not in series
if made query like
Select Doc.Code,Doc.DataAccept,DocTypes.Name,Org.Name
From
Doc,DocTypes,Org
Where Doc.Type=DocTypes.Code AND Doc.Org=Org.Code AND Doc.Code AND Doc.Code < 100;
than it's ok
|Code|DataAccept|Name|Name|
1 | - | - | - |
2 | - | - | - |
3 | - | - | - |
4 | - | - | - |
5 | - | - | - |
if Doc.Code < 1000 than again it's not in series
I try to use ORDER BY Code
Select Doc.Code,Doc.DataAccept,DocTypes.Name,Org.Name
From
Doc,DocTypes,Org
Where Doc.Type=DocTypes.Code AND Doc.Org=Org.Code AND Doc.Code AND Doc.Code
ORDER BY Code DESC;
and
Select Doc.Code,Doc.DataAccept,DocTypes.Name,Org.Name
From
Doc,DocTypes,Org
Where Doc.Type=DocTypes.Code AND Doc.Org=Org.Code AND Doc.Code AND Doc.Code
ORDER BY Code ASC;
but in result i have ordered not in series
What i did missing here ?
Thank you for your time , and forgive my English
"-" - it is a normal data , use it just for represent.

SELECT Doc.Code,Doc.DataAccept,DocTypes.Name,Org.Name
FROM Doc LEFT OUTER JOIN DocTypes JOIN Org
ON Doc.Type=DocTypes.Code AND Doc.Org=Org.Code;
WHERE Doc.Code < 1000 ;
ORDER BY 1
this explanation might be useful as well.

Related

MySQL monthly diffs

i spent lot of time to search a solution to my problem. i think i'm near the solution but my final request doesn't work...
first of all, i have a table that represent water index based on 10 minutes sampling.
----------------------------------
| DateTime | Counter |
----------------------------------
| 2020-05-13 15:00:03 | 38450 |
| 2020-05-13 15:10:03 | 38454 |
| 2020-05-15 15:00:03 | 38500 |
| 2020-06-02 12:10:03 | 38510 |
| 2020-06-15 12:10:03 | 38600 |
----------------------------------
Some samples could be not present in the table
so i would like to extract a table to see my consumptions by days, week, month, year
i have found many examples, but none works as i expect...
for the example table above, i expect to get:
------------------------------------------------------------------------------
| fromDateTime | toDateTime | fromCounter | toCounter | diff |
------------------------------------------------------------------------------
| 2020-05-13 15:00:03 | 2020-06-02 12:10:03 | 38450 | 38510 | 60 |
| 2020-06-02 12:10:03 | 2020-06-15 12:10:03 | 38510 | 38600 | 90 |
------------------------------------------------------------------------------
i have writen a query
select mt1.DateTime as fromDateTime,
mt2.DateTime as toDateTime,
mt1.Counter as fromCounter,
mt2.Counter as toCounter,
(mt2.Counter - mt1.Counter) as diff
from WaterTest as mt1
left join WaterTest as mt2
on mt2.DateTime=(
select max(dd.datetime) as DateTime from (SELECT MIN(DateTime) as DateTime
FROM WaterTest as mt3
WHERE month(mt3.DateTime) = month(mt1.DateTime + INTERVAL 1 month)
union ALL
select max(DateTime) as DateTime
from WaterTest as mt4
where month(mt4.DateTime) = month(mt1.DateTime)
) as dd
)
But MySql results with an error saying "Field 'mt1.DateTime' unknown in where clause"
is someone can help to find where i'm wrong ?
Am I on the good way to achieve this ?
(and for sure, if there is a more powerfull request.... :) )

How can I select all rows which have been inserted in the last day?

I have a table like this:
// reset_password_emails
+----+----------+--------------------+-------------+
| id | id_user | token | unix_time |
+----+----------+--------------------+-------------+
| 1 | 2353 | 0c274nhdc62b9dc... | 1339412843 |
| 2 | 2353 | 0934jkf34098joi... | 1339412864 |
| 3 | 5462 | 3408ujf34o9gfvr... | 1339412894 |
| 4 | 3422 | 2309jrgv0435gff... | 1339412899 |
| 5 | 3422 | 34oihfc3lpot4gv... | 1339412906 |
| 6 | 2353 | 3498hfjp34gv4r3... | 1339412906 |
| 16 | 2353 | asdf3rf3409kv39... | 1466272801 |
| 7 | 7785 | 123dcoj34f43kie... | 1339412951 |
| 9 | 5462 | 3fcewloui493e4r... | 1339413621 |
| 13 | 8007 | 56gvb45cf3454g3... | 1339424860 |
| 14 | 7785 | vg4er5y2f4f45v4... | 1339424822 |
+----+----------+--------------------+-------------+
Each row is an email. Now I'm trying to implement a limitation for sending-reset-password email. I mean an user can achieve 3 emails per day (not more).
So I need an query to check user's history for the number of emails:
SELECT count(1) FROM reset_password_emails WHERE token = :token AND {from not until last day}
How can I implement this:
. . . {from now until last day}
Actually I can do that like: NOW() <= (unix_time + 86400) .. But I guess there is a better approach by using interval. Can anybody tell me what's that?
Your expression will work, but has 3 problems:
the way you've coded it means the subtraction must be performed for every row (performance hit)
because you're not using the raw column value, you couldn't use an index on the time column (if one existed)
it isn't clear to read
Try this:
unix_time > unix_timestamp(subdate(now(), interval '1' day))
here the threshold datetime is calculated once per query, so all of the problems above have been addressed.
See SQLFiddle demo
You can convert your unix_time using from_unixtime function
select r.*
from reset_password_emails r
where now() <= from_unixtime(r.unix_time) - interval '1' day
Just add the extra filters you want.
See it here: http://sqlfiddle.com/#!9/4a7a9/3
It evaluates to no rows because your given data for unix_time field is all from 2011
Edited with a sqlfiddle that show the conversion:
http://sqlfiddle.com/#!9/4a7a9/4

Creating Temporary Column Order By Slow

So basically what I'm trying to do is get gained experience, ordering it, then only displaying top 5 or 50. Now note that I'm not SQL expert but I have knowledge of indexes as well as file sorting. The query that I have is filesorting most likely due to "gained_xp" not being a index-- let alone even a column as it's only temporary. There's no clear explanation how to fix this as I'm trying to contain it all in one query. I'm trying to sort nearly 13k rows with that number only expanding. I'd also need the number of rows to be dynamic as well as the time since. Any help would be appreciated. Thank you
Explain Output: Using where; Using temporary; Using filesort
Indexes include: time userid override overallXp overallLevel overallRank
The closest I've gotten to order all rows (which never ends up completing and ends in a mysql reboot) are:
SELECT FROM_UNIXTIME(time, '%Y-%m-%d'), t_u.userid as uid, MAX(t_u.OverallXP)-(SELECT overallXP FROM track_updates WHERE `userid` = t_u.userid AND `time`>'1394323200' ORDER BY id ASC LIMIT 1) as gained_xp
FROM track_updates t_u
WHERE t_u.time>'1394323200'
GROUP BY t_u.userid
If I'd run a query that selects only one user and works correctly is:
SELECT FROM_UNIXTIME(time, '%Y-%m-%d'), (t_u.overallXP)-(SELECT overallXP FROM track_updates WHERE `userid`='1' ORDER BY `id` ASC LIMIT 1) as gained_xp, t_u.userid
FROM track_updates t_u
WHERE t_u.userid='1' AND t_u.time>'1393632000'
ORDER BY t_u.time DESC
LIMIT 1
Sample Data per request:
____________________________________________________________________
| id | userid | time | overallLevel | overallXP | overallRank |
| 1 | 1 | 1394388114 | 1 | 1 | 1 |
| 2 | 1 | 1394389114 | 2 | 10 | 1 |
| 3 | 2 | 1394388114 | 1 | 1 | 2 |
| 4 | 2 | 1394389114 | 1 | 5 | 2 |
| 5 | 2 | 1394390114 | 2 | 7 | 2 |
Output (most recent time; gained xp current-initial; ordered by gain_xp):
____________________________________________
| id | time | userid | gained_xp |
| 1 | March 9th 2014 | 1 | 9 |
| 2 | March 9th 2014 | 2 | 6 |

MySQL: optimize query for scoring calculation

I have a data table that I use to do some calculations. The resulting data set after calculations looks like:
+------------+-----------+------+----------+
| id_process | id_region | type | result |
+------------+-----------+------+----------+
| 1 | 4 | 1 | 65.2174 |
| 1 | 5 | 1 | 78.7419 |
| 1 | 6 | 1 | 95.2308 |
| 1 | 4 | 1 | 25.0000 |
| 1 | 7 | 1 | 100.0000 |
+------------+-----------+------+----------+
By other hand I have other table that contains a set of ranges that are used to classify the calculations results. The range tables looks like:
+----------+--------------+---------+
| id_level | start | end | status |
+----------+--------------+---------+
| 1 | 0 | 75 | Danger |
| 2 | 76 | 90 | Alert |
| 3 | 91 | 100 | Good |
+----------+--------------+---------+
I need to do a query that add the corresponding 'status' column to each value when do calculations. Currently, I can do that adding the following field to calculation query:
select
...,
...,
[math formula] as result,
(select status
from ranges r
where result between r.start and r.end) status
from ...
where ...
It works ok. But when I have a lot of rows (more than 200K), calculation query become slow.
My question is: there is some way to find that 'status' value without do that subquery?
Some one have worked on something similar before?
Thanks
Yes, you are looking for a subquery and join:
select s.*, r.status
from (select s.*
from <your query here>
) s left outer join
ranges r
on s.result between r.start and r.end
Explicit joins often optimize better than nested select. In this case, though, the ranges table seems pretty small, so this may not be the performance issue.

MySQL using GROUP BY to group by multiple columns

I'd like to use GROUP BY multiple columns, I think it's best to start with an example:
SELECT
eventsviews.eventId,
showsActive.showId,
showsActive.venueId,
COUNT(*) AS count
FROM eventsviews
INNER JOIN events ON events.eventId = eventsviews.eventId
INNER JOIN showsActive ON showsActive.eventId = eventsviews.eventId
WHERE events.status = 1
GROUP BY showsActive.venueId, showsActive.showId, showsActive.eventId
ORDER BY count DESC
LIMIT 100;
Output:
| *eventId* | *showId* | *venueId* | *count* |
+-----------+----------+-----------+---------+
[...snip...]
| 95 | 92099 | 9770 | 32 |
| 95 | 105472 | 10702 | 32 |
| 3804 | 41225 | 8165 | 17 |
| 3804 | 41226 | 8165 | 17 |
| 923 | 2866 | 5451 | 14 |
| 923 | 20184 | 5930 | 14 |
[...snip...]
What I would like instead:
| *eventId* | *showId* | *venueId* | *count* |
+-----------+----------+-----------+---------+
| 95 | 92099 | 9770 | 32 |
| 3804 | 41226 | 8165 | 17 |
| 923 | 20184 | 5930 | 14 |
So, I want my data grouped by eventId, but only once for each showId and venueId ...
I actually have a SQL query that does that, but it has 8 subqueries and is as slow as a T-Ford ... And since this is executed on every page load, speeding things up looks like a good idea!
There are a few questions like this, and I've tried many different things, but I've been at this query for an hour and I can't seem to get it to work as I want :-(
Thanks!
You probably want either a min or a max on showid, and then not include it in the group by, I can't tell which because looking at your "prefered" resultset, you have both.
If you want your data grouped by eventId, group just by eventId and you'll get exactly the result you're looking for.
This is a MySQL feature (?) that it allows you to select non-aggregate columns, in which case it will return the first row available. In other DBMS it's achieved by DISTINCT ON, which is not available in MySQL.