GROUP BY Precedence in MySQL - mysql

I have two tables; one is called rules and the other data. The Rules table holds events, which have a description, id and date_created and is simply used to categorize events.
The data table has a date and id column; This stores the actual dates of an event, as events can span up to months long in dates.
My issue is this: I wish to select everything from data and group it by date, so each date is represented only once. However, the event with the most recent creation date should have precedence if there is a collision, i.e. two events happen on the same day. Here is what I've tried, which doesn't offer control over date_created:
SELECT d.date, r.description FROM data d LEFT JOIN rules r ON d.id = r.id GROUP BY date ORDER BY d.date
I haven't included date_created yet because I'm stuck, and not sure where it should go in the query to get the desired effect. Any ideas would be greatly appreciated!

From your question it seems to me that at first you need to select maximum date of event creation and then using subquery you can desired result:
SELECT a.date, b.description
FROM data a
INNER JOIN (
SELECT id, description,MAX(date_created) as mdate
FROM rules
GROUP BY id,description
) b ON a.id = b.id AND a.date = b.mdate

Related

How to select data from 2 tables by date

I have two tables:
In this table I have all employees:
Employe (id_employe, name, tel)
In this table I have all employees who are present:
Present (id_present, date, #id_empoye)
Now, I want to select all employees who are absent (all of employees who are not in the table present) with the date of absence.
I'm sorry for by bad English, and I want a help please!
Here's my sql query:
select id_employe, date from employe, absence where id_employe not in
(select id_personnel from absence group by date) group by id_employe
order by date asc;
What you first want to do is use a subquery to get all of your employees with a record for every day that was a work day. I am assuming that if any one person showed up for work that day, it was a work day. So, I select every distinct work date and join it onto every employee. I say ON 1=1 because that condition is always true and will give me a record for every employee and the work day.
Then, I take that temp table and I join on the Present table. If an employee was present on a work day, he will have a record joined on from the Present table, so I can look for only records where there was no join, i.e. p.id_present IS NULL.
WITH WorkDateTable AS (
SELECT e.id_employe, p.work_date
FROM Employe e LEFT JOIN (SELECT DISTINCT work_date FROM Present) p ON 1=1)
SELECT wd.id_employe, wd.work_date AS AbsenceDate
FROM WorkDateTable wd
LEFT JOIN Present p ON p.work_date = wd.work_date AND p.id_employe = wd.id_employe
WHERE p.id_present IS NULL
ORDER BY AbsenceDate, wd.id_employe
Note that date is a reserved word and you cannot use that for a field, that is why I changed it to work_date. Your final result is a list of work dates and the ID of who was absent on that day.
If you want to know who was absent on a particular date or range of dates, you just need to add a clause to the WHERE statement at the end.
EDIT:
MySQL does not support the use of the WITH clause. Therefore, move the statement in the WITH to inside the FROM statement like this:
SELECT wd.id_employe, wd.work_date AS AbsenceDate
FROM (SELECT e.id_employe, p.work_date
FROM Employe e LEFT JOIN (SELECT DISTINCT work_date FROM Present) p ON 1=1) wd
LEFT JOIN Present p ON p.work_date = wd.work_date AND p.id_employe = wd.id_employe
WHERE p.id_present IS NULL
ORDER BY AbsenceDate, wd.id_employe
This query should work for either MySQL or Oracle searches.
Assuming you only want the employees who are not present on a particular day, you can use the following query:
SELECT e.*
FROM employee e
WHERE NOT EXISTS (
SELECT id_present FROM present WHERE id_employee = e.id_employee AND date = <date>
);
This would give you employees who are absent on <date> date. As we are querying for one date only, no sorting is needed.

WHERE clause behaving in the wrong way

i want to create a weekly report using a php script. in the mysql query of this, i want to take out tables that functioned during the last week by using its timestamp in the meantime get the other values(especially the counts of unique users and overall users) since the creation date of those tables. but at the moment its returning incorrect data in terms of counts where the counts are given only within the last week not since the creation of project.
this happens inside a loop so for the example query im using table table_1
QUERY
SELECT DISTINCT b.ID, name, accountname, c.accountID, status,
total_impr, min(a.timestamp), max(a.timestamp),COUNT(DISTINCT userid)
AS unique_users,COUNT(userid) AS overall_users
FROM table_1 a INNER JOIN logs b on a.ID = b.ID INNER JOIN
accounts c on b.accountID = c.accountID
WHERE a.timestamp > DATE_ADD(NOW(), INTERVAL -1 WEEK

Merging 3 Tables, Limiting 1 Table With Multiple Fields Needed

Been looking into this for awhile. Hoping someone might be able to provide some insight. I have 3 tables. All of which I'm grabbing multiple columns, but the 3rd I need to limit the output to just the most recent timestamp entry, BUT still display multiple columns.
If I have the following data [ Please see SQL Fiddle ]:
http://sqlfiddle.com/#!2/84b91/6
The fiddle is a list of (names) in Table1(users), (job_name,years) in Table2(job), and then (score, timestamp) in Table3(job_details). All linked together by the users id.
I am definitely not great at MYSQL. I know I'm missing something.. possibly a series of JOINs. I have been able to get Table 1, Table 2 and one column of Table 3 by doing this:
select a.id, a.name, b.job_name, b.years,
(select c.timestamp
from job_details as c
where c.user_id = a.id
order by c.timestamp desc limit 1) score
from users a, job as b where a.id = b.user_id;
At this point, I can get multiple column data on the first two columns, limit the 3rd to one value and sort that value on the last timestamp...
My question is: How does one go about adding a second column to the limit? In the example in the fiddle, I'd like to add the score as well as the timestamp to the output.
I'd like the output to be:
NAME, JOB, YEARS, SCORE, TIMESTAMP. The last two columns would only be the last entry in job_details sorted by the most recent TIMESTAMP.
Please let me know if more information is required! Thank you for your time!
T
Try this:
select a.id, a.name, b.job_name, b.years, c.timestamp, c.score
from users a
INNER JOIN job as b ON a.id = b.user_id
INNER JOIN (SELECT jd.user_id, jd.timestamp, jd.score
FROM job_details as jd
INNER JOIN (select user_id, MAX(timestamp) as tstamp
from job_details
GROUP BY user_id) as max_ts ON jd.user_id = max_ts.user_id
AND jd.timestamp = max_ts.tstamp
) as c ON a.id = c.user_id
;

Group by week, display empty weeks - with where clause

We are attempting to count how many unique telephone numbers called a particular number each day, with 0 (or NULL) for days with no calls. To simplify the data schema, our table contains four fields:
| id | fromz | toz | date |
fromz: inbound call number
toz: number called
date: yyyy-mm-dd
When all we need to know is how many unique numbers called by each day - and do not care what number was called - it is simple to include no-calls days in results.
We JOIN to another table containing only sequential dates: calendar
| id | date |
date:yyyy-mm-dd
SELECT p.fromz, count(unique(p.fromz)), p.date FROM phones p
RIGHT OUTER JOIN calendar c ON
p.date = c.date
GROUP BY c.date
If no p.fromz on c.date, the result for that p.date is "0" (or NULL)
Problem arises when we begin to sort by numbers called:
SELECT p.fromz, count(unique(p.fromz)), p.date FROM phones p
RIGHT OUTER JOIN calendar ON
p.date = c.date
WHERE p.toz = "#myNumber"
GROUP BY c.date
Because there are no WHERE toz = #myNumber on some days we only get results on days when (WHERE) there were calls to #myNumber.
Any suggestions?
I've modified some of your field names slightly. I'm not sure if this 100% meets your use-case, but if it doesn't, you should be able to figure it out from here. Basically, move your current WHERE condition into the ON clause.
SELECT p.fromz, count(distinct p.fromz), p.callDate, c.theDate FROM phones p
RIGHT OUTER JOIN calendar c ON
p.callDate = c.theDate AND p.toz = 2125555555
GROUP BY c.theDate
SQLFiddle
Full Disclosure
This is not standards-compliant. For a compliant query, take a look at Ollie's answer and simply move the p.toz part from the WHERE to the ON to get the results you want.
You are very close.
You're using a nasty MySQL nonstandard extension to GROUP BY and it is driving you crazy, as it has driven many others crazy before you.
http://dev.mysql.com/doc/refman/5.5/en/group-by-extensions.html
You need to follow the rules for standard GROUP BY. These rules specify that each column mentioned in the SELECT clause must be either (1) also mentioned in the GROUP BY clause or (2) an aggregate function.
There are two problems in your query. One is that you mention p.date instead of c.date in your SELECT clause. That p.date will be null if there aren't any items on the date in question in your phones table. The second item is that you're mentioning p.fromz twice.
I think your basic aggregate query should look like this http://sqlfiddle.com/#!2/0ef4e/3/0:
SELECT p.toz,
COUNT(DISTINCT p.fromz) AS unique_calling_number_count,
c.date
FROM phones AS p
RIGHT OUTER JOIN calendar AS c ON p.date = c.date
GROUP BY p.toz, c.date
ORDER BY c.date, p.toz
That will summarize call-origination numbers by day and call-destination numbers.
Then, when you need to filter your phones records according to some kind of criterion, do that in a subquery as follows.
SELECT p.toz,
COUNT(DISTINCT p.fromz) AS unique_calling_number_count,
c.date
FROM (
SELECT * /* filtering subquery */
FROM phones
WHERE toz = "#myNumber"
) AS p
RIGHT OUTER JOIN calendar AS c ON p.date = c.date
WHERE p.toz = "#myNumber"
GROUP BY p.toz, c.date
ORDER BY c.date, p.toz
Here's an example of this working. http://sqlfiddle.com/#!2/0ef4e/2/0 Thanks to #PatrickQ for noticing the WHERE at the wrong level of the query.

join on sub query returns fails

Trying to join a table "fab_qouta.qoutatype" to at value inside a sub query "fab_status_members.statustype" but it returns nothing.
If I join the 2 tables directly in a query the result is correct.
Like this:
select statustype, takst
from
fab_status_members AS sm
join fab_quota as fq
ON fq.quotatype = sm.statustype
So I must be doing something wrong, here the sub query code, any help appreciated
select
ju.id,
name,
statustype,
takst
from jos_users AS ju
join
( SELECT sm.Members AS MemberId, MaxDate , st.statustype
FROM fab_status_type AS st
JOIN fab_status_members AS sm
ON (st.id = sm.statustype) -- tabels are joined
JOIN
( SELECT members, MAX(pr_dato) AS MaxDate -- choose members and Maxdate from
FROM fab_status_members
WHERE pr_dato <= '2011-07-01'
GROUP BY members
)
AS sq
ON (sm.members = sq.members AND sm.pr_dato = sq.MaxDate)
) as TT
ON ju.id = TT.Memberid
join fab_quota as fq
ON fq.quotatype = TT.statustype
GROUP BY id
Guess the problem is in the line: join fab_quota as fq ON fq.quotatype = TT.statustype
But I can't seem to look through it :-(
Best regards
Thomas
It looks like you are joining down to the lowest combination of per member with their respective maximum pr_dato value for given date. I would pull THIS to the FIRST query position instead of being buried, then re-join it to the rest...
select STRAIGHT_JOIN
ju.id,
ju.name,
fst.statustype,
takst
from
( SELECT
members,
MAX(pr_dato) AS MaxDate
FROM
fab_status_members
WHERE
pr_dato <= '2011-07-01'
GROUP BY
members ) MaxDatePerMember
JOIN jos_users ju
on MaxDatePerMember.members = ju.ID
JOIN fab_status_members fsm
on MaxDatePerMember.members = fsm.members
AND MaxDatePerMember.MaxDate = fsm.pr_dato
JOIN fab_status_type fst
on fsm.statustype = fst.id
JOIN fab_quota as fq
on fst.statusType = fq.quotaType
I THINK I have all of what you want, and let me reiterate in simple words what I think you want. Each member can have multiple status entries (via Fab_Status_Members). You are looking for all members and what their MOST RECENT Status is as of a particular date. This is the first query.
From that, whatever users qualify, I'm joining to the user table to get their name info (first join).
Now, back to the complex part. From the first query that determined the most recent date status activity, re-join back to that same table (fab_status_members) and get the actual status code SPECIFIC to the last status date for that member (second join).
From the result of getting the correct STATUS per Member on the max date, you need to get the TYPE of status that code represented (third join to fab_status_type).
And finally, from knowing the fab_status_type, what is its quota type.
You shouldn't need the group by since the first query is grouped by the members ID and will return a single entry per person (UNLESS... its possible to have multiple status types in the same day in the fab_status_members table... unless that is a full date/time field, then you are ok)
Not sure of the "takst" column which table that comes from, but I try to completely qualify the table names (or aliases) they are coming from, buy my guess is its coming from the QuotaType table.
... EDIT from comment...
Sorry, yeah, FQ for the last join. As for it not returning any rows, I would try them one at a time and see where the break is... I would start one at a time... how many from the maxdate query, then add the join to users to make sure same record count returned. Then add the FSM (re-join) for specific member / date activity, THEN into the status type... somewhere along the chain its missing, and the only thing I can think of is a miss on the status type as any member status would have to be associated with one of the users, and it should find back to itself as that's where the max date originated from. I'm GUESSING its somewhere on the join to the status type or the quota.