MySQL data against each month - mysql

I have a table for users like this
id | username | name | join_date
-----+-------------+--------+-------------
1 | asdasd | name1 | timestamp
2 | asdas1 | name2 | timestamp
3 | asdas2 | name3 | timestamp
4 | asdas3 | name4 | timestamp
Each user needs to pay for a monthly subscription. Needs to take the report if user paid or not.
So I created another table for adding month data ( admin will add each month manually )
id | month_number | year
----+----------------+---------
1 | 02 | 2017 // Case Feb 2014
3 | 03 | 2017 // Case Mar 2014
how to connect these two tables ?

The easiest way would be to just join them inside queries.
The easiest way for that would be to just put it inside the where clause.... SELECT payment.month_number, payment.year, users.username FROM users, payment WHERE (users.id = payment.id) AND (users.username = asdasd)

You will need a table to track the subscriptions (second table is not needed actually). subscriptions can have user id as Foreign Key, subscription_date and amount columns, e.g.:
id | user_id | subscription_date | amount
----+-----------+-------------------+--------
1 | 2 | 2017-03-01 | 100
1 | 1 | 2017-02-01 | 100

if possible Please add the column user_id to the month_date table
and, try this
SELECT *
FROM users u
LEFT JOIN month_date m
ON u.id = m.user_id

Related

GroupBy ID but keep multiple values

I have the following MySQL table:
+----------+----------+---------+-------------+------------+----------+----------+-----------+
| queue_id | email_id | user_id | customer_id | send_date | campaign | approved | scheduled |
+----------+----------+---------+-------------+------------+----------+----------+-----------+
| 1 | 1 | 1 | 1 | 2018-10-30 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 | 2018-10-30 | 1 | 1 | 1 |
| 3 | 2 | 1 | 1 | 2018-11-02 | 1 | 1 | 1 |
| 4 | 2 | 2 | 1 | 2018-11-02 | 1 | 0 | 1 |
| 5 | 2 | 3 | 1 | 2018-11-02 | 1 | 1 | 1 |
+----------+----------+---------+-------------+------------+----------+----------+-----------+
Where the email_id, user_id, and customer_id are all foreign keys.
What I need to do is return the send_date, subject (which is apart of the email table that the email_id references), and name (which is apart of the business table that the user_id references) but only for columns where the approved column is true. The idea is to ultimately display the data to a user in an HTML table where the table would look like the following (using the sample data provided):
+--------------------+--------------------------+---------------+
| October 30th, 2018 | Subject for email_id "1" | View Approved |
| November 2nd, 2018 | Subject for email_id "2" | View Approved |
+--------------------+--------------------------+---------------+
Whenever the user would click on the "View Approved" cell, then it would display all of the business names that approved that particular email.
I tried using the following query, but it is only returning one value in the name column:
SELECT
DATE_FORMAT(q.`send_date`, "%M %D, %Y") AS `date_visited`,
e.`subject`,
b.`name`
FROM
`email_queue` AS q
INNER JOIN
`email` AS e ON q.`email_id` = e.`email_id`
INNER JOIN
`user` AS u ON q.`user_id` = u.`user_id`
INNER JOIN
`business` AS b ON u.`business_id` = b.`business_id`
WHERE
q.`approved` = true
GROUP BY
e.`email_id`
ORDER BY
q.`send_date` DESC
How can I structure my query to where it would return all of the business names in the name column instead of just one?
You can get all the unqiue business names in a Comma separated string, using Group_Concat() function with Distinct clause.
Try:
GROUP_CONCAT(DISTINCT b.`name` SEPARATOR ',') AS name
instead of:
b.`name`
Note:
You can avoid the usage of Distinct clause, if there would not be any duplicate user_id (for a specific email_id), thus ensuring that b.name is also unique.
You can also use any separator, instead of comma. For eg: to use separator as pipe character |, you would write the query as:
GROUP_CONCAT(DISTINCT b.nameSEPARATOR '|') AS name

MySql: get MIN record in INNER JOIN If a field is null, or change criteria

I have a query between two tables.
First table is a list of users
+----+-------+-----------+
| id | name | expire_on |
+----+-------+-----------+
| 22 | JOHN | (null) |
| 44 | SMITH | (null) |
| 55 | DOE | 5 |
+----+-------+-----------+
Where "expire_on" can be NULL, but if compiled it is the expire of his subscription, in days.
And I have a list of transactions:
+----+----------------+-----------------+--------------+-------------+----------------------+
| id | id_member_card | amount_original | amount_final | description | utc_date_t |
+----+----------------+-----------------+--------------+-------------+----------------------+
| 1 | 22 | 12 | 12 | (null) | 2017-05-01T10:11:12Z |
| 2 | 22 | 50 | 50 | (null) | 2018-02-01T10:20:30Z |
| 3 | 44 | 7 | 7 | (null) | 2018-02-02T07:50:40Z |
| 4 | 22 | 9 | 9 | (null) | 2018-03-01T10:00:14Z |
| 5 | 44 | 5 | 5 | (null) | 2018-03-03T08:09:10Z |
| 6 | 22 | 0 | 0 | RENEW | 2018-05-02T11:22:33Z |
| 7 | 55 | 12 | 12 | (null) | 2018-05-03T10:20:30Z |
+----+----------------+-----------------+--------------+-------------+----------------------+
I have this starting points:
1) The user "expires" after 365 days of his very first transaction. The id 44 will expire on the 02-02-2019... > BUT >
2) If the user has a field "expire_on", he expires after the X days and not anymore the 365. In my example, id 55 is expired on the 07-05-2018.
3) If in the transaction list there is a RENEW, the user expires 365 days after this transaction renew and not anymore from the first one. Id 22 will expire only on the 02-05-2019 (pratically, we could consider a RENEW transaction as his first_transaction, if this can help to write a smarter query ) > BUT
If the user has the expire_on set, he expires X days after this renew (if the id 22 had expire_on set on, for example, let's say, 10 days, he would be expired on 12-05-2018 and not anymore 02-05-2019).
I hope that I'm clear.
Now MySql query, that I cannot complete considering the RENEW or not.
First of all, this is the link to the fiddle: http://sqlfiddle.com/#!9/16a3a/1
And this is the query:
SELECT member_card.id AS id,
member_card.name,
member_card.expire_on,
ts1.* FROM member_card
INNER JOIN (
SELECT member_card.id,
MIN(transaction.utc_date_t) AS first_transaction,
MAX(transaction.utc_date_t) AS last_transaction,
IFNULL (
DATE(DATE_ADD(MAX(transaction.utc_date_t), INTERVAL expire_on DAY)) ,
DATE(DATE_ADD(MAX(transaction.utc_date_t), INTERVAL 365 DAY))
)
AS final_expire ,
SUM(transaction.amount_final) AS balance
FROM transaction
INNER JOIN member_card ON transaction.id_member_card = member_card.id
GROUP BY member_card.id ) AS ts1 ON member_card.id = ts1.id
WHERE ( final_expire BETWEEN '2019-02-01' AND '2019-02-28' )
GROUP BY member_card.id
With my query, I would expect to find id 44, because his first transaction is made on 2018-02-01, so he will expire on the february 2019. But my query considers only LAST transaction (see MAX aggregate).
So, I need to search and looking for:
If exists a RENEW:
If yes, take this date and sum 365 (OR the custom expire date)
If no, take MIN transaction.
Thank you very much for your support.
Tryng to solve
I could also get the last renew transactions, with another query:
SELECT id_member_card , MAX(utc_date_t) AS last_transaction_renew
FROM transaction
WHERE description IS NOT NULL
GROUP BY id_member_card
and substitute these found id_member_card to the others, using this last_transaction_renew inside that IFNULL, but, how?

How to get last record for group?

I have a table called tbl_chat and tbl_post.
The tbl_chat is given as follows.
|--------------------------------------------------------------------------------|
| chat_id | message | from_user | to_user | post_id |send_date |
|--------------------------------------------------------------------------------|
| 1 | Hi | 23 | A | 35 | 2016-04-01 17:35|
| 2 | Test | 24 | A | 35 | 2016-04-02 01:35|
| 3 | Thut | A | 23 | 35 | 2016-04-02 03:35|
| 4 | test | A | 24 | 35 | 2016-04-02 12:35|
| 5 | Hi | 23 | A | 35 | 2016-04-03 17:35|
|--------------------------------------------------------------------------------|
Now, in the chat table we can see three users are interacting with each other. The Admin (A), user with id = 23 and user = 24.
So there is basically two chat thread.
One between A and 23
Another between A and 24.
I want a query which will show the two chat threads, with the last chat message. Just like in case of facebook chat list showing all the chat-threads with mentioning the last chat.
I am writing a query like this.
SELECT * FROM tbl_chat, tbl_post
WHERE tbl_post.post_id = tbl_chat.post_id
AND tbl_post.post_id = '39'
GROUP BY tbl_chat.chat_from
ORDER BY date DESC
The query has a problem. It is first retrieving all the chats and grouping it w.r.t. chat_from and then ORDERING it Descending-wise.
So first it's creating the group, and then ordering the group.
Also, the first query produces three group, taking the reply message from Admin as a separate group. Since GROUP BY chat_from.
How can I solve this issue?
EDIT:-
I would be grateful if someone can build the query in Active-Records of Codeigniter.
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(chat_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,message VARCHAR(20) NOT NULL
,from_user VARCHAR(12)
,to_user VARCHAR(12)
,post_id INT NOT NULL
,send_date DATETIME NOT NULL
);
INSERT INTO my_table VALUES
(1,'Hi' ,'23','A' ,35,'2016-04-01 17:35:00'),
(2,'Test','24','A' ,35,'2016-04-02 01:35:00'),
(3,'Thut','A' ,'23',35,'2016-04-02 03:35:00'),
(4,'test','A' ,'24',35,'2016-04-02 12:35:00'),
(5,'Hi' ,'23','A' ,35,'2016-04-03 17:35:00');
SELECT a.*
FROM my_table a
JOIN
( SELECT LEAST(from_user,to_user) user1
, GREATEST(from_user,to_user) user2
, MAX(send_date) send_date
FROM my_table
GROUP
BY user1
, user2
) b
ON b.user1 = LEAST(a.from_user,a.to_user)
AND b.user2 = GREATEST(a.from_user,a.to_user)
AND b.send_date = a.send_date;
+---------+---------+-----------+---------+---------+---------------------+
| chat_id | message | from_user | to_user | post_id | send_date |
+---------+---------+-----------+---------+---------+---------------------+
| 4 | test | A | 24 | 35 | 2016-04-02 12:35:00 |
| 5 | Hi | 23 | A | 35 | 2016-04-03 17:35:00 |
+---------+---------+-----------+---------+---------+---------------------+
You can use NOT EXISTS() :
SELECT * FROM tbl_chat
INNER JOIN tbl_post
ON tbl_post.post_id = tbl_chat.post_id
WHERE NOT EXISTS(SELECT 1 FROM tbl_chat s
WHERE tbl_chat.from_user IN(s.from_user,s.to_user)
AND tbl_chat.to_user IN(s.from_user,s.to_user)
AND tbl_chat.date < s.date)
Although date field looks like DATE type, which is curious - how would you find the difference between two messages at the same day?

MYSQL - Show sum of total work_time but only display results from last updated date_time

Sorry for the confusing Title. I have been struggling with this query for quite a long time and I will do my best to explain what I am looking for.
I have 3 tables I am trying to pull from. We will call them:
headers
details
users
The headers table contains two important fields:
ref_num
headers_uid
The details table has the following important rows:
details_uid
headers_uid
work_time
user_uid
disposition
date_time
The users table has the following:
user_uid
username
An example of the details table which contains the majority of the information I need is as follows:
details_uid | headers_uid | work_time | user_uid | disposition | date_time
1 | 10 | 25:00 | 5 | o | 2013-07-02 12:14:48
2 | 10 | 10:00 | 7 | p | 2013-07-02 13:55:37
3 | 10 | 5:00 | 5 | c | 2013-07-02 15:04:28
4 | 12 | 7:00 | 5 | o | 2013-07-02 15:20:21
5 | 12 | 12:00 | 7 | p | 2013-07-02 15:35:27
6 | 12 | 3:00 | 7 | c | 2013-07-02 15:40:19
What I'm trying to do is display the headers.refnum, sum of total work_time for the unique user for ALL details.details_uids with the same details.headers_uid and only the LAST disposition of the details.headers_uid for the each user. The results must look for a specific date_time (I generally search by > CURDATE() to grab events for today) Also, instead of displaying the user_uid, I will be searching within a WHERE clause by users.username (I have usernames stored in a txt file which is turned into an IN statement).
Ideally, this is what I would like to see:
ref_num | work_time | username | disposition |
A10 | 30:00 | mike | c |
A10 | 10:00 | james | p |
A12 | 7:00 | mike | o |
A12 | 15:00 | james | c |
Any help is greatly appreciated! I know this will probably involve a good deal of join statements and subqueries and I've been banging my head on the table trying to get it right. I know this would be much easier using php, but sadly, I don't have php access at work yet (don't ask..)
I think this does what you want:
select h.ref_num, sum(d.work_time), u.username, d.disposition
from details d join
headers h
on d.headers_uid = h.headers_uid join
users u
on d.user_uid = u.user_uid
where d.disposition = (select disposition
from details d2
where d2.headers_uid = d.headers_uid and
d2.users_uid = d.users_uid
order by date_time desc
limit 1
)
group by h.ref_num, u.username, d.disposition;
The key is the where clause that selects the last disposition for a given set of details records.

Mysql include column with no rows returned for specific dates

I would like to ask a quick question regarding a mysql query.
I have a table named trans :
+----+---------------------+------+-------+----------+----------+
| ID | Date | User | PCNum | Customer | trans_In |
+----+---------------------+------+-------+----------+----------+
| 8 | 2013-01-23 16:24:10 | test | PC2 | George | 10 |
| 9 | 2013-01-23 16:27:22 | test | PC2 | Nick | 0 |
| 10 | 2013-01-24 16:28:48 | test | PC2 | Ted | 10 |
| 11 | 2013-01-25 16:36:40 | test | PC2 | Danny | 10 |
+----+---------------------+------+-------+----------+----------+
and another named customers :
+----+---------+-----------+
| ID | Name | Surname |
+----+---------+-----------+
| 1 | George | |
| 2 | Nick | |
| 3 | Ted | |
| 4 | Danny | |
| 5 | Alex | |
| 6 | Mike | |
.
.
.
.
+----+---------+-----------+
I want to view the sum of trans_in column for specific customers in a date range BUT ALSO include in the result set, those customers that haven't got any records in the selected date range. Their sum of trans_in could appear as NULL or 0 it doesn't matter...
I have the following query :
SELECT
`Date`,
Customer,
SUM(trans_in) AS 'input'
FROM trans
WHERE Customer IN('George','Nick','Ted','Danny')
AND `Date` >= '2013-01-24'
GROUP BY Customer
ORDER BY input DESC;
But this will only return the sum for 'Ted' and 'Danny' because they only have transactions after the 24th of January...
How can i include all the customers that are inside the WHERE IN (...) function, even those who have no transactions in the selected date range??
I suppose i'll have to join them somehow with the customers table but i cannot figure out how.
Thanks in advance!!
:)
In order to include all records from one table without matching records in another, you have to use a LEFT JOIN.
SELECT
t.`Date`,
c.name,
SUM(t.trans_in) AS 'input'
FROM customers c LEFT JOIN trans t ON (c.name = t.Customer AND t.`Date` >= '2013-01-24')
WHERE c.name IN('George','Nick','Ted','Danny')
GROUP BY c.name
ORDER BY input DESC;
Of course, I would mention that you should be referencing customer by ID, and not by name in your related table. Your current setup leads to information duplication. If the customer changes their name, you now have to update all related records in the trans table instead of just in the customer table.
try this
SELECT
`Date`,
Customer,
SUM(trans_in) AS 'input'
FROM trans
inner join customers
on customers.Name = trans.Customer
WHERE Customer IN('George','Nick','Ted','Danny')
GROUP BY Customer
ORDER BY input DESC;