I have 2 tables which I want to join and retrieve some specific data. These are my tables.
tbl_user (reg_id, l_name, f_name, status)
tbl_payments (pay_id, reg_id, mem_plan, from_date, to_date, bill_no, payed_date)
What I need to do is select and view the users who have due payments. To do that I want to get the user details where "status=0" from tbl_user and join the 2 tables together and the conditions are to_date< current date, difference between [current date and the to_date] < 31 and filter by the Max value of to_date.
What I did so far gives me a result according to above mentioned conditions except it dosen't filter by the MAX(to_date). This is my query.
SELECT
A.reg_id,
A.f_name,
A.l_name,
B.mem_plan,
B.from_date,
Max(B.to_date) AS to_date,
B.bill_no,
B.payed_date
FROM
tbl_user A,
tbl_payments B
WHERE
A.status = 0
AND A.reg_id = B.reg_id
AND Date(Now()) >= Date(B.to_date)
AND Datediff(Date(Now()), Date(b.to_date)) < 31
GROUP BY
a.reg_id, b.mem_plan, b.from_date, b.bill_no, b.payed_date;
I'm not very familiar with MYSQL, So please someone tell me what I did wrong or if this query is not up to the standard.
Here are some sample data to work on.
tbl_user ( [M1111,Jon, Doe,0], [M1112,Jane,Doe,1],[M1113,Jony,Doe,0] )
tbl_payment ( [1,M1111,Monthly,2018-05-14,2018-06-14,b123,2018-05-14],[2,M1112,3Months,2018-02-03,2018-05-03,b112,2018-02-03],[3,M1113,Monthly,2018-06-14,2018-07-14,b158,2018-06-14],[4,M1111,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[5,M1113,Monthly,2018-06-06,2018-07-06,b158,2018-06-06],[6,M1111,Monthly,2018-07-05,2018-08-05,b345,2018-07-05] )
Assuming current date is 2018-07-17, The expecting result should be this
[M1111,Jon,Doe,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[M1113,Jony,Doe,Monthly,2018-06-14,2018-07-14,b158,2018-06-14]
Instead of that, my query gives me this.
[M1111,Jon,Doe,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[M1113,Jony,Doe,Monthly,2018-06-06,2018-07-06,b158,2018-06-06],
[M1113,Jony,Doe,Monthly,2018-06-14,2018-07-14,b158,2018-06-14]
I wrote another query which gives me the result set exactly as i want. But I'm not sure whether it's up to the standards. If someone can simplify this or make it better, appreciate very much.
SELECT A.reg_id,A.f_name,A.l_name,D.mem_plan,D.from_date,D.to_date,D.bill_no,D.payed_date
FROM tbl_user A
JOIN (SELECT B.reg_id,B.mem_plan,B.from_date,B.to_date,B.bill_no,B.payed_date
FROM tbl_payments B
JOIN (
SELECT reg_id, MAX(to_date) as to_date
FROM tbl_payments
WHERE DATE(NOW()) >= DATE(to_date) AND DATEDIFF(DATE(NOW()), DATE(to_date))<31
GROUP BY reg_id) C
ON B.reg_id = C.reg_id AND B.to_date= C.to_date) D
ON A.reg_id = D.reg_id
WHERE A.status=0;
I believe having won't work here and that your second query is about as good as it gets. I've condensed it a little here:
SELECT A.reg_id,f_name,l_name,mem_plan,from_date,to_date,bill_no,payed_date
FROM #tbl_user A
JOIN #tbl_payments B ON A.reg_id = b.reg_id
JOIN (
SELECT reg_id, MAX(to_date) as max_to_date
FROM #tbl_payments
WHERE DATE(NOW()) >= DATE(to_date) AND DATEDIFF(DATE(NOW()), DATE(to_date))<31
GROUP BY reg_id
) C ON B.reg_id = C.reg_id AND B.to_date= C.max_to_date
WHERE A.status=0;
I am trying to do a regular join but select the latest entry from the history_items table using a where clause.
SELECT h.history_id,
Date_format(From_unixtime(h.timestamp), '%d %m %Y') AS 'date',
h.status,
h.product_id,
p.serial_number,
p.product_name,
p.site_name,
p.site_postcode,
Date_format(From_unixtime(i.timestamp), '%d %m %Y') AS 'last_update',
i.feedback
FROM history h
LEFT JOIN products p
ON h.product_id = p.product_id
LEFT JOIN history_items i
ON h.history_id = i.history_id
WHERE i.timestamp = (SELECT Max(i.timestamp)
FROM history_items)
GROUP BY i.history_id
ORDER BY h.timestamp DESC
I am selecting Max(i.timestamp) - this is still not returning the latest entry from the history_items table.
I think your problem is here:
WHERE i.timestamp = (SELECT Max(i.timestamp)
FROM history_items)
The i should not be there, it should be Max(timestamp) not Max(i.timestamp).
Else Mysql will really select the value of the i.timestamp row. So if your timestamp is 1 it will evaluate to this:
WHERE 1 =(SELECT Max(1) FROM hsitory_items)
Which basically will be
WHERE i.timestamp = i.timestamp
I bet you get the idea now. That's why all rows are returned.
Since you are anyways sorting on timestamp saying ORDER BY h.timestamp DESC you actually don't need the below pointed WHERE condition at all. Also the subquery in below pointed code is wrongly referring the column as already mentioned in other answer
WHERE i.timestamp = (SELECT Max(i.timestamp)
FROM history_items)
I am looking for how many number of columns I can use in "order by" clause, for e.g. I have a column NAME asc, START_DATE asc, SKU_GROUP asc and want to add SKU_NAME asc in order clause. I am currently using 1 group by but for curiosity how many can be used within MySQL?
SELECT pop.SUB_ELEMENT, pop.NAME, sub_element.LDESC AS SUB_NAME, DATE_FORMAT(journey_visits.START_DATE, '%b %d %Y %h:%i %p' ) AS START_DATE, visit_sku.IS_CHECK,visit_sku.TYPE AS `SKU_TYPE`,brand.LDESC AS `SKU_GROUP`,sku.LDESC AS `SKU_NAME`,sku.SKU AS `MATERIAL` FROM visit_sku
LEFT JOIN journey_visits ON journey_visits.VISIT_ID = visit_sku.VISIT_ID
LEFT JOIN pop ON journey_visits.POP_ID = pop.POPID
LEFT JOIN sub_element ON sub_element.SubElementID=pop.SUB_ELEMENT
LEFT JOIN sku ON visit_sku.SKU_ID = visit_sku.SKU_ID AND visit_sku.SKU_ID = sku.SKU
LEFT JOIN brand ON sku.brandid = brand.BRANDID
WHERE DATE(journey_visits.START_DATE) BETWEEN '2016-04-01' AND '2016-04-03'
ORDER BY NAME, START_DATE, SKU_NAME
There is no limit, you can order by or group by all columns in a result set, although the latter would be useless.
This is actually part of a Massive SQL query, but I had this code working, and now I cant seem to figure out why its not finding the last appointment record.
What I am trying to do is join all the other appointments onto themselves to find out which one is the last one. And all my results appear to be null. But this is not correct because my data definitely have appointments. So I think there is something wrong with my select query. Any help would be great.
SELECT `animal_id`,
FROM_UNIXTIME(`lastappointment`.`appointmentdata_starttime`,'%D %M %Y') AS 'Last Appointment'
FROM `animal`
LEFT JOIN (
SELECT `lAppointment`.*
FROM `appointment` AS `lAppointment`
LEFT JOIN `appointment` AS `nlAppointment`
ON `nlAppointment`.`appointmentdata_starttime` <= NOW()
AND `nlAppointment`.`appointmentdata_starttime` > `lAppointment`.`appointmentdata_starttime`
AND `nlAppointment`.`appointmentdata_animal` = `lAppointment`.`appointmentdata_animal`
WHERE `lAppointment`.`appointmentdata_starttime` <= NOW()
AND `nlAppointment`.`appointment_id` IS NULL
) AS `lastappointment`
ON `animal_id` = `lastappointment`.`appointmentdata_animal`
WHERE `animaldata_active` IS NOT NULL
GROUP BY animal_id;
Using LEFT JOINs to get the MAX() is the slowest method you can think of. I recommend you to change the inner query like this (using GROUP BY):
SELECT `animal_id`,
FROM_UNIXTIME(`lastappointment`.`last_appointment`, '%D %M %Y') AS 'Last Appointment'
FROM `animal`
LEFT JOIN (
SELECT MAX(appointmentdata_starttime) AS last_appointment,
appointmentdata_animal
FROM appointment
WHERE appointmentdata_starttime <= NOW()
GROUP BY appointmentdata_animal
) AS `lastappointment`
ON `animal_id` = `lastappointment`.`appointmentdata_animal`
WHERE `animaldata_active` IS NOT NULL
-- GROUP BY animal_id; --BTW, this group_by is not needed
I have an assignment to create a twitter like database. And in this assignment i have to filter out the trending topics. My idea was to count the tweets with a specific tag between the date the tweet was made and 7 days later, and order them by the count.
I have the following 2 tables i am using for this query :
Table Tweet : id , message, users_id, date
Table Tweet_tags : id, tag, tweet_id
Since mysql isn't my strong point at all im having trouble getting any results from the query.
The query i tried is :
Select
Count(twitter.tweet_tags.id) As NumberofTweets,
twitter.tweet_tags.tag
From twitter.tweet
Inner Join twitter.tweet_tags On twitter.tweet_tags.tweet_id = twitter.tweet.id
WHERE twitter.tweet_tags.tag between twitter.tweet.date and ADDDATE(twitter.tweet.date, INTERVAL 7 day)
ORDER BY NumberofTweets
The query works, but gives no results. I just can't get it to work. Could you guys please help me out on this, or if you have a better way to get the trending topics please let me know!
Thanks alot!
This is equivalent to your query, with table aliases to make it easier to read, with BETWEEN replaced by two inequality predicates, and the ADDDATE function replaced with equivalent operation...
SELECT COUNT(s.id) As NumberofTweets
, s.tag
FROM twitter.tweet t
JOIN twitter.tweet_tags s
ON s.tweet_id = t.id
WHERE s.tag >= t.date
AND s.tag <= t.date + INTERVAL 7 DAY
ORDER
BY NumberofTweets
Two things pop out at me here...
First, there is no GROUP BY. To get a count by "tag", you want at GROUP BY tag.
Second, you are comparing "tag" to "date". I don't know your tables, but that just doesn't look right. (I expect "date" is a DATETIME or TIMESTAMP, and "tag" is a character string (maybe what my daughter calls a "hash tag". Or is that tumblr she's talking about?)
If I understand your requirement:
For each tweet, and for each tag associated with that tweet, you want to get a count of the number of other tweets, that have a matching tag, that are made within 7 days after the datetime of the tweet.
One way to get this result would be to use a correlated subquery. (This is probably the easiest approach to understand, but is probably not the best approach from a performance standpoint).
SELECT t.id
, s.tag
, ( SELECT COUNT(1)
FROM twitter.tweet_tags r
JOIN twitter.tweet q
ON q.id = r.tweet_id
WHERE r.tag = s.tag
AND q.date >= t.date
AND q.date <= t.date + INTERVAL 7 DAY
) AS cnt
FROM twitter.tweet t
JOIN twitter.tweet_tags s
ON s.tweet_id = t.id
ORDER
BY cnt DESC
Another approach would be to use a join operation:
SELECT t.id
, s.tag
, COUNT(q.id) AS cnt
FROM twitter.tweet t
JOIN twitter.tweet_tags s
ON s.tweet_id = t.id
LEFT
JOIN twitter.tweet_tags r
ON r.tag = s.tag
LEFT
JOIN twitter.tweet q
ON q.id = r.tweet_id
AND q.date >= t.date
AND q.date <= t.date + INTERVAL 7 DAY
GROUP
BY t.id
, s.tag
ORDER
BY cnt DESC
The counts from both of these queries assume that tweet_tags (tweet_id, tag) is unique. If there are any "duplicates", then including the DISTINCT keyword, i.e. COUNT(DISTINCT q.id) (in place of COUNT(1) and COUNT(q.id) respectively) would get you the count of "related" tweets.
NOTE: the counts returned will include the original tweet itself.
NOTE: removing the LEFT keywords from the query above should return an equivalent result, since the tweet/tag (from t/s) is guaranteed to match itself (from r/q), as long as the tag is not null and the tweet date is not null.
Those queries are going to have problematic performance on large sets. Appropriate covering indexes are going to be needed for acceptable performance:
... ON twitter.tweet_tags (tag, tweet_id)
... ON twitter.tweet (date)