Achieve data between particular date in Mysql - mysql

I have three tables named User,Role and Balance_updates. User table hold info about user,Role depicts type of user like Customer,Admin,Manager and Balance_updates store all transaction regarding balance i.e it store history about transaction related to balance.
Tables
User
+-----------------------+--------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+-------------------+-------+
| username | varchar(20) | NO | PRI | NULL | |
| password | varchar(32) | NO | | NULL | |
| email | varchar(50) | YES | | NULL | |
| role_id | int(11) | NO | MUL | NULL | |
| mobile_wallet_balance | double(20,2) | NO | | 0.00 | |
| merit_point | bigint(20) | YES | | NULL | |
| status | int(11) | NO | | NULL | |
| is_auto_btm_enabled | tinyint(1) | YES | | 0 | |
| created_at | datetime | YES | | NULL | |
| updated_at | timestamp | YES | | CURRENT_TIMESTAMP | |
| gender | varchar(20) | YES | | NULL | |
| validity | date | YES | | NULL | |
| status_desc | text | YES | | NULL | |
+-----------------------+--------------+------+-----+-------------------+-------+
Role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(25) | NO | UNI | NULL | |
| description | varchar(255) | YES | | NULL | |
| value | varchar(25) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
Balance_updates
+------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(15) | NO | | NULL | |
| role_id | int(11) | YES | | NULL | |
| amount | double(20,2) | YES | | NULL | |
| updated_at | timestamp | NO | | CURRENT_TIMESTAMP | |
+------------+--------------+------+-----+-------------------+----------------+
Data in Balance_updates
Objective
I want to generate all users and their respective balance in any given date;
For example if i want the balance statement for a given date 2012-12-28 it should generate latest balance from Balance_updates.
What I have tried
SELECT DISTINCT (
u.username
), r.value, u.amount AS `amount`
FROM Balance_updates u
INNER JOIN Role r ON u.role_id = r.id
WHERE u.amount > 0.0 && UNIX_TIMESTAMP( u.updated_at ) < UNIX_TIMESTAMP( '2013-1-3 23:59:59' )
ORDER BY r.value, UNIX_TIMESTAMP( u.updated_at ) DESC
RESULT and PROBLEM
As you expect it is returning all values from Balance_updates i.e every other User transaction recorded.
Question:
1.How can i achieve latest balance statement of a user in a particular date.If in that date user balance is not changed then show his balance in previous time last changed.
Any help will be appreciated;

Not tested, but I have the feeling this could work (and could be optimised).
SELECT DISTINCT u.username, r.value, u.amount AS `amount`
FROM Balance_updates u
INNER JOIN Role r ON u.role_id = r.id
WHERE u.updated_at = (
SELECT MAX(inner_u.updated_at)
FROM Balance_updates AS inner_u
WHERE
inner_u.username = u.username
&& amount > 0
&& UNIX_TIMESTAMP( inner_u.updated_at ) < UNIX_TIMESTAMP( '2013-1-3 23:59:59' )
)
ORDER BY r.value, UNIX_TIMESTAMP( u.updated_at ) DESC
Just one off-topic piece of advice:
add a surrogate key to table User (e.g. User.id); make it the primary key
replace column Balance_updates.username with (e.g.) Balance_updates.user_id, and store a reference to User.id (a foreign key).
or
change column Balance_updates.username to a VARCHAR(20) to match the type of User.username

Related

sql query count number of record in a join

I have to extract the list of POS(point of service) from pos table, based on location name:
POS
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| address | varchar(200) | YES | | NULL | |
| country | varchar(45) | YES | | NULL | |
| location | varchar(100) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
so, it would be something like :
select *
from pos
where location = 'new york';
Now , from the table mission i have to count the number of POS (pos_name), and if this number is greater than a number coming from a subquery, pos register should not be shown.
mission
| id | int(11) | NO | PRI | NULL | auto_increment |
| team_name | varchar(45) | YES | | NULL | |
| team_photo | varchar(255) | YES | | NULL | |
| pos_name | varchar(45) | YES | | NULL | |
| pos_id | int(11) | YES | | NULL | |
| product_category | varchar(45) | YES | | NULL | |
| product_platform | varchar(45) | YES | | NULL | |
| created_by | int(11) | YES | | NULL | |
| judged_by | int(11) | YES | | NULL | |
| selfie_photo | varchar(255) | YES | | NULL | |
| like_score | int(11) | YES | | NULL | |
| star_score | float | YES | | NULL | |
| feedback_recommendation | varchar(2000) | YES | | NULL | |
| created_at | timestamp | YES | | CURRENT_TIMESTAMP | |
| updated_at | timestamp | YES | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| sent_date | timestamp | YES | | NULL | |
| locked | tinyint(1) | YES | | 0 | |
+-------------------------+---------------+------+-----+-------------------+-----------------------------+
so until now i developed following sql query :
SELECT p.id,p.name
FROM missions m join pos p
on m.pos_id = p.id
where p.location = 'new york'
having count(m.pos_name) < (select count(*)
from product_category);
but this part of code
having count(m.pos_name)
should be something like that :
select count(*)
from missions
group by pos_name;
because without group by statement i will recieve a sum of all pos, but i need to check it for a group, not for all of them.
Any suggestion ?
I thing you need the data with group by with condition then try this
SELECT p.id,p.name
FROM missions m join pos p
on m.pos_id = p.id
where p.location = 'new york'
group by m.pos_name
having count(m.pos_name) < (select count(*)
from product_category);
Just add group by m.pos_name it will work.
You can check Here

How to COUNT with condition while distinct join MySQL?

I have two tables:
mysql> DESCRIBE swaps;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user1_id | int(11) | NO | | NULL | |
| user2_id | int(11) | NO | | NULL | |
| hasto | int(11) | NO | | NULL | |
| requested | datetime | NO | | NULL | |
| accepted | datetime | YES | | NULL | |
| swapped1 | datetime | YES | | NULL | |
| swapped2 | datetime | YES | | NULL | |
| rejected | datetime | YES | | NULL | |
| rejected_by | int(11) | YES | | NULL | |
+-------------+----------+------+-----+---------+----------------+
mysql> DESCRIBE messages;
+-----------+----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+-------------------+----------------+
| msg_id | int(11) | NO | PRI | NULL | auto_increment |
| sender_id | int(11) | NO | | NULL | |
| msg | text | NO | | NULL | |
| msg_time | datetime | NO | | CURRENT_TIMESTAMP | |
| swap_id | int(11) | NO | | NULL | |
| seen | datetime | YES | | NULL | |
+-----------+----------+------+-----+-------------------+----------------+
and query that I adjusted from this question
SELECT s.*, m.*
FROM swaps as s
JOIN messages as m
ON (s.id= m.swap_id AND m.msg_time=
(SELECT MAX(msg_time) FROM messages WHERE messages.swap_id = s.id));
as a result I single row for every swap and information about last sent message within this swap. I want to add the count of messages that have not jet been seen (m.seen IS NULL).
I tried different approaches but always get error. What I want is to add count of messages in corresponding swap with seen IS NULL to my result set. Would appreciate any suggestions.
You can add the count as a subquery:
SELECT s.*, m.*,
(SELECT COUNT(*) FROM messages m2 WHERE m2.seen IS NULL) as seen_is_null
FROM swaps s JOIN
messages m
ON s.id= m.swap_id AND
m.msg_time =(SELECT MAX(m2.msg_time) FROM messages m2 WHERE m2.swap_id = s.id));
It seems curious to be counting over all messages, but that is what the question asks for. You can, of course, introduce a correlation clause to count for a given swap or something else.

mysql query using 4 tables to produce small report

I'm having trouble getting a query to work. 4 tables are used in this query. I want a report looking like this...
Name Success Failure
jdn 5 1
wer 0 3
I want to produce data for the last 24 hours. Here is a sample query I tried and didn't work.
select r.name as jid,
i.id as theid,
(select sum(counter) as scount
from WebServicesIfSummarySuccess
where id=theid
and dtime between date_sub(now(),interval 24 hour) and now()
and sum(counter) >0 and sum(counter) is not null
group by id
) as success,
(select sum(counter) as fcount
from WebServicesIfSummaryFailure
where id=theid
and dtime between date_sub(now(),interval 24 hour) and now()
and sum(counter) >0 and sum(counter) is not null
group by id
) as failure
from router r, interface i
where r.rid = i.rid
and r.name like '%wi%' ;
Here are the table layouts.
router
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| rid | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | char(120) | NO | MUL | | |
| pop | char(10) | NO | MUL | | |
| popid | tinyint(3) unsigned | NO | | 0 | |
+-------+---------------------+------+-----+---------+----------------+
interface
+-------------+---------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | char(255) | NO | MUL | | |
| rid | int(11) | NO | MUL | 0 | |
| speed | bigint(11) | YES | | NULL | |
| description | char(255) | YES | | NULL | |
| status | enum('active','inactive') | YES | | active | |
+-------------+---------------------------+------+-----+---------+----------------+
Failure and Success are 2 separate tables
+---------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| dtime | datetime | NO | PRI | NULL | |
| counter | bigint(20) | NO | | NULL | |
| rate | int(11) | YES | | NULL | |
+---------+------------------+------+-----+---------+-------+

Getting an error saying there's an unknown table in the field list when that table exists

I'm trying to output the amount of discount given to a customer by finding the difference, but I keep getting Error #1109 Unknown table 'item' in field list when I do have a table named item in my current DB.
I'm using this query:
SELECT orderpay.orderid , cust.name , (orderpay.totalpay - actualCost) as `discount amount`
FROM cust , orderpay , tran , item,
(SELECT sum(item.unitprice * tran.quantity) ) as actualCost
WHERE item.itemid = tran.itemid AND (orderpay.totalpay - actualCost) > 0
GROUP BY item.itemid
Here are my table structures:
cust
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| custid | int(5) | NO | PRI | 0 | |
| name | varchar(22) | YES | | NULL | |
| email | varchar(33) | YES | | NULL | |
| address | varchar(29) | YES | | NULL | |
| city | varchar(21) | YES | | NULL | |
| country | varchar(14) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
item
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| itemid | int(5) | NO | PRI | 0 | |
| name | varchar(94) | YES | | NULL | |
| unitprice | decimal(6,2) | YES | | NULL | |
| cat | varchar(12) | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
orderpay
+----------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------+------+-----+---------+-------+
| orderid | int(5) | NO | PRI | 0 | |
| date | varchar(10) | YES | | NULL | |
| custid | int(5) | YES | | NULL | |
| cardnum | varchar(25) | YES | | NULL | |
| cardtype | varchar(25) | YES | | NULL | |
| totalpay | decimal(10,2) | YES | | NULL | |
+----------+---------------+------+-----+---------+-------+
tran
+----------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------+------+-----+---------+-------+
| orderid | int(5) | NO | PRI | 0 | |
| itemid | int(5) | NO | PRI | 0 | |
| quantity | int(2) | YES | | NULL | |
+----------+--------+------+-----+---------+-------+
Consider changing your query like below
SELECT *,
(totalpay - computed_price) as `discount amount`
FROM
(
SELECT orderpay.orderid ,
cust.name ,
orderpay.totalpay ,
sum(item.unitprice * `tran`.quantity) as computed_price
FROM cust JOIN `tran` ON item.itemid = tran.itemid
JOIN orderpay ON cust.some_column = orderpay.some_column
JOIN item ON cust.some_column = item.some_column
GROUP BY item.itemid
) tab
WHERE (totalpay - computed_price) > 0
Select totalpaid.custid, (totalprices.total - totalpaid.total) as `discount` FROM
(
SELECT sum(totalpay) as total, custid
FROM orderpay
GROUP BY custid
) as totalpaid JOIN
(
SELECT sum(item.unitprice * tran.quantity) as total, orderpay.custid
FROM orderpay JOIN tran ON orderpay.orderid=tran.orderid JOIN item ON tran.itemid item.itemid
GROUP BY orderpay.custid
) as totalprices ON totalpaid.custid = orderpay.custid
As a side note, you should not use this to calculate the total as if prices changed (and they do change in time) you calculation will be all messed up. Instead you should remember the discount for each order when you create it.
VERY IMPORTANT
Also it scares me that you have a field called cardnum | varchar(25) you should never ever keep the CC numbers.

Update MySQL table based on results for joining to tables

I have three tables, emails, person_details and data_providers. Basically all of my users id, email, and current assigned data_providers_id are stored in the emails table.
The second table, person_details contains demographic information collected by multiple data providers, each row identified by an emails_id that is relational to the emails.id data_providers_id that is relational to the third table data_providers.id
The third table, data_providers contains each of my data providers id, name, and precedence.
Basically, a users information could be collected from multiple sources, and I need to UPDATE emails set data_providers_id = based on a select that would JOIN the person_details table and the data_providers table sorting by data_providers.precedence DESC then person_details.import_date ASC and use the first value (highest precedence, then oldest import_date).
I was trying to build the query, but my subquery is returning more than one row. This query is a little over my head, hoping someone more experienced with complex queries might be able to point me in the right direction.
UPDATE emails
SET emails.data_providers_id =
SELECT person_details.data_providers_id
FROM person_details
LEFT JOIN data_providers ON person_details.data_providers_id = data_providers.id
ORDER BY data_providers.percent_payout ASC, person_details.import_date ASC ;
Here are some details about the three tables if this helps. Any guidance would be MUCH appreciated. Thanks in advance :)
emails table:
+-------------------+---------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------------------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| data_providers_id | tinyint(3) unsigned | NO | MUL | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
+-------------------+---------------------+------+-----+---------------------+----------------+
person_details:
+-------------------+---------------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------------------+-------+
| emails_id | int(11) unsigned | NO | PRI | NULL | |
| data_providers_id | tinyint(3) unsigned | NO | PRI | NULL | |
| fname | varchar(255) | YES | | NULL | |
| lname | varchar(255) | YES | | NULL | |
| address_line1 | text | YES | | NULL | |
| address_line2 | text | YES | | NULL | |
| city | varchar(255) | YES | | NULL | |
| state | varchar(2) | YES | | NULL | |
| zip5 | varchar(5) | YES | | NULL | |
| zip4 | varchar(4) | YES | | NULL | |
| home_phone | varchar(10) | YES | | NULL | |
| mobile_phone | varchar(10) | YES | | NULL | |
| work_phone | varchar(10) | YES | | NULL | |
| dob | date | YES | | NULL | |
| gender | varchar(1) | YES | | NULL | |
| ip_address | varchar(15) | NO | | NULL | |
| source | varchar(255) | NO | | NULL | |
| optin_datetime | datetime | NO | MUL | NULL | |
| import_date | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------------+---------------------+------+-----+---------------------+-------+
data_providers table:
+-----------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+----------------+
| id | tinyint(3) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| precedence | int(2) | YES | | 0 | |
+-----------------+---------------------+------+-----+---------+----------------+
To use a SELECT as an expression you have to put it in parentheses. And to get the first value, use LIMIT 1:
UPDATE emails
SET emails.data_providers_id = (
SELECT person_details.data_providers_id
FROM person_details
LEFT JOIN data_providers ON person_details.data_providers_id = data_providers.id
WHERE person_details.emails_id = emails.id
ORDER BY data_providers.percent_payout ASC, person_details.import_date ASC
LIMIT 1) ;