MySQL: Aggregation the similar value fields from Table 1 - php

I'm trying to create a query from two tables, Table 1 contains a contract between the company and the customer.
Table 2 contains a statement payments.
What I want to do is: assembling late payments from Table 2 values, so that the value of each batch 250$ and displayed as follows:
____________________________________
Client | late payments | total
____________________________________
John | 2 | 500 (250*2)
____________________________________
Table2 like this:enter image description here

First use Concat for create date and cast string as date and compare with paydate at last use group by and calculate sum or count of late paid
SELECT contract_id,count(contract_id) late_payments,sum(paid) total FROM `table`
where cast(Concat(year.'-',month,'-',day) as date) < paydate
Group by contract_id

Related

Select distinct by highest or lowest value

I'm working on a track and field ranking database in MySQL/PHP5 whereby I'm struggling to find the best way to query results per unique athlete by highest value.
just
SELECT distinct name, event
FROM results
sample database
name | event | result
--------------------------
athlete 1 | 40 | 7.43
athlete 2 | 40 | 7.66
athlete 1 | 40 | 7.33
athlete 1 | 60 | 9.99
athlete 2 | 60 | 10.55
so let's say that in this case I'd like to rank the athletes on the 40m dash event by best performance I tried
SELECT distinct name, event
FROM results
WHERE event = 40
ORDER by result DESC
but the distinct only leaves the first performance (7.43) of the athlete which isn't the best (7.33). Is there an easy way other than creating a temp table first whereby the results are ordered first and performing a select on the temp table afterwards?
You might be interested in group by:
SELECT name, min(result) as result
FROM results
WHERE event = 40
GROUP BY name
This gives you the best result per athlete.
As suggested by spencer, you can also order the list by appending this:
ORDER BY min(result) ASC
The problem is that the columns used in the ORDER BY aren't specified in the DISTINCT. To do this, you need to use an aggregate function to sort on, and use a GROUP BY to make the DISTINCT work.
SELECT distinct name, event
FROM results
WHERE event = 40
GROUP BY name
ORDER by result DESC

fetch rows dynamically from one table and get values from other table sum it up and insert into target table

x table has columns(Agency,datac)Y table has columns(Agencyname,total)
EXAMPLE
Agency | datac
NET | 100
GOO | 300
NET | 100
GOO | 100
Agencyname | total
NET |
GOO |
first customer adds Agencyname then it gets update on table Y From a dropdown menu in html i have made user to either choose NET OR GOO but what i want is how many values they may enter in table X.
i want their total sum to be inserted into table Y. so that my expected output looks like this
Agencyname | total
NET | 200
GOO | 400
The most straight forward way is probably an update with a subquery;
UPDATE TableY
SET total = (SELECT SUM(datac) FROM TableX WHERE Agency=AgencyName)
An SQLfiddle to test with.
UPDATE Y
SET Y.total = X.Total
FROM TABLE_Y Y INNER JOIN
(
SELECT Agency, SUM(datac) AS Total
FROM TABLE_X
GROUP BY Agency
) X
ON Y.Agencyname = X.Agency
SQL FIDDLE TEST
SELECT agency, SUM(datac) FROM x GROUP BY agency
You want to combine this with INSERT INTO.
Although I do not see much sense in caching this easy-to-compute values...

Select a column only if id is distinct MySQL

I have the following table:
AMAZON_ID | DATE | STATUS
1 | 01/03/2014 | Pending
1 | 01/03/2014 | Shipped
2 | 01/04/2014 | Pending
3 | 01/05/2014 | Cancelled
4 | 01/06/2014 | Pending
How can I select the earliest date from table where status is equals Pending where the count of id is not more then one, it should be like the following:
AMAZON_ID | DATE | STATUS
2 | 01/04/2014 | Pending
I can not figure that out, this is what I have so far but its not working:
SELECT date
FROM table
WHERE status = 'Pending'
AND COUNT(id) < 2
ORDER BY date ASC
LIMIT 1;
Use a subquery to GROUP BY the id's that have COUNT of 1. Make sure your id is IN the results of this subquery, with a status of pending. Then ORDER BY date and LIMIT to the first result.
SELECT date
FROM table
WHERE
status = 'Pending' AND
id IN (
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = 1
)
ORDER BY date ASC
LIMIT 1;
One thing you can do is use a WHERE IN, and use a select statement to populate the WHERE clause with distinct ids
SELECT date
FROM table
WHERE status = 'Pending'
AND id IN (SELECT DISTINCT id FROM table)
ORDER BY date ASC
LIMIT 1;
It depends on what you really mean by "count of id is not more than one".
I have renamed your column date to ts to make the queries valid SQL (as DATE is a SQL function so it may confuse parsers). See the SQL fiddle for the complete schema I used and the example queries.
Option 2: one row per ID total
In this case you have a problem because you want a query to get one piece of information (the minimum date) that is based on a different piece of information about the same table. This means that you need to queries, luckily you can just join the data of the two queries and filter appropriately.
SELECT data.id, status, MIN(ts)
FROM data
JOIN (SELECT id, COUNT(*) AS amount FROM data GROUP BY id) AS totals
ON totals.id = data.id
WHERE
status = "Pending"
AND totals.amount < 2
GROUP BY data.status;
Option 1 (easy): only one pending row per ID
NOTE: this answer does not answer the OP's question
In this case, the situation is quite easy as you can just filter all your rows with status "pending", the minimum date and the total amount of rows that match your result and, after the aggregation (i.e.: using HAVING) filter those that have less than 2 amounts.
In SQL that would be:
SELECT id, status, MIN(ts) AS minTS, COUNT(*) AS amount
FROM data
WHERE
status = "Pending"
GROUP BY id, status
HAVING amount < 2

how can i count specific field multi rows of mysql using php

how can I count Mysql Field Rows?
For example I have table called student_attendance where we have 4 fields: absent, present, holiday, leave.
There is list of 10+ students, each student value will go to its own field, like if for one student we selected absent, 1 value will go to absent field and if someone select present, 1 value will go to present field.
Now what i want is
Each time attendance take, new row insert in student_attendance table for the student.
So if there are 10 Rows in student_attendance table, how can i + all of them
Like if there are 10 rows of present field, 3 rows are empty and 7 rows have 1 value, how can i count it so that the total value of specific field 1+1+1+1+1+1+1 can comes in php so it show 7 ?
SELECT SUM(present) AS presence_days
FROM student_attendance
This will result:
+---------------+
| presence_days |
+---------------+
| 7 |
| |
+---------------+
Example SQL (Demo):
select count(*) from table_name where present_field=1;
Try this:
SELECT SUM(absent), SUM(present), SUM(holiday), SUM(leave)
FROM student_attendance
GROUP BY sudentId;

sql query to find users with three or more months in debt

I have a little app (PHP/MySQL) to manage condos. There's a condos table, apartments table, a owners table and a account table.
In the account table I have the fields month_paid and year_paid (among others).
Each time someone pays the monthly fee, the table is updated with the number of the month and the year.
Here's some sample table structure:
condos table:
+----+------------+---------+
| id | condo_name | address |
+----+------------+---------+
apartments table:
+----+----------------+----------+
| id | apartment_name | condo_id |
+----+----------------+----------+
owners table:
+----+--------------+------------+
| id | apartment_id | owner_name |
+----+--------------+------------+
account table:
+----+----------+----------+------------+-----------+
| id | owner_id | condo_id | month_paid | year_paid |
+----+----------+----------+------------+-----------+
So, if I have a record in account table like this, it means this owner paid August 2012:
+----+----------+----------+------------+-----------+
| id | owner_id | condo_id | month_paid | year_paid |
+----+----------+----------+------------+-----------+
| 1 | 1 | 1 | 8 | 2012 |
+----+----------+----------+------------+-----------+
What I would like to know is how to make a SQL query (using PHP) to get the owners with three or more months in debt or, in other words, owners that have not payed the fee for the last three months or more.
If possible, the data should be grouped by condo, like this:
CONDO XPTO:
Owner 1: 3 months debt
Onwer 2: 5 months debt
CONDO BETA
Owner 1: 4 months debt
Onwer 2: 6 months debt
Thanks
You need to write a query something like this:
SELECT
*
FROM
owners
JOIN
account
ON
owners.id = account.owners_id
WHERE
CONCAT( account.year_paid , '-' , account.month_paid , '-01') <= DATE_ADD( NOW(), INTERVAL -3 MONTH );
Sadly that's about all I can give you with the information you have provided. If you could show more detailed table structure, I could help you out more.
You are making it harder on yourself by storing it this way. Now you need to calculate the difference in months yourself. You cannot just check on months, because e.g. in january you also need to take the year into consideration.
SELECT *
FROM owners
JOIN account ON owners.Id=account.ownersId
WHERE (
account.year_paid = year(now)
AND (
month(now)-account.month_paid>=3
)
) OR (
account.year_paid = year(now)-1
AND (
month(now)>=3
OR (
account.month_paid - month(now) <= 10
AND month(now) = 1
)
OR (
account.month_paid - month(now) <= 11
AND month(now) = 2
)
)
) OR (
account.year_paid < year(now)-1
)
Better to just store the lastpaid time in a datetime collumn so you can use date functions.
To fix your account table. The DROP COLUMNs are optional, you might want keep them if they have dependencies.
ALTER TABLE account ADD COLUMN date_paid DATETIME;
UPDATE account SET date_paid = CONCAT(year_paid,'-',month_paid,'-01');
--ALTER TABLE account DROP COLUMN year_paid;
--ALTER TABLE account DROP COLUMN month_paid;
This is how you’d get your data. I used LEFT OUTER JOINs in case you have any missing owner or condo records.
SELECT c.condo_name,
o.owner_name,
min(PERIOD_DIFF(DATE_FORMAT(now(), '%Y%m'), DATE_FORMAT(date_paid, '%Y%m'))) min_months_debt
FROM account a
LEFT OUTER JOIN condos c ON (c.id = a.condo_id)
LEFT OUTER JOIN owners o ON (a.owner_id = o.id)
WHERE a.date_paid <= DATE_ADD(NOW(), INTERVAL -3 MONTH)
GROUP BY c.condo_name, o.owner_name
ORDER BY c.condo_name
P.S. The above only works for condo owners who have made at least one payment. If you want to see condo owners who have never paid then you’re going to have to associate condos with owners outside of the accounts table. Or perhaps you create an account record when you associate a condo with an owner, in which case you don’t have a problem.
If I understand correct you have two different fields for moth and for year. Why?
If you had one field say paid_date this query would work for you
SELECT owner_id from account WHERE NOW()>DATE_ADD(paid_date, INTERVAL 3 MONTH)
If you can change fielfd then sorry. I hope this is helpful.
UPD:
Then I'd suggest you concatenation of two fields (year and month) in the query to make it look like real date in YYYY-MM-DD format and use it in DATE_ADD function instead of paid_date field
Try this,
select o.owner_name,c.condo_name from owners o join account a join condos c
on o.id=a.owner_id and c.id =a.condo_id where year(curdate())=a.year_paid
and a.month_paid<month(curdate())-3
I haven't seen any answers that actually produce what you are looking for. The following calculates the months in debt by calculating the current month minus the most recent payment date. It then concatenates the results into a string:
select c.condo_name, o.owner_name,
cast(YEAR(now)*12+MONTH(now)) - MAX(year_paid*12+month_paid) as varchar(255)), ' month(s) debt'
from account a join
owners o
on o.id = a.owner_id join
condos c
on c.id = a.condo_id
group by c.condo_name,, o.owner_name
order by 1, 2
If you want only delinquent payers, then add a where clause to the effect of:
where YEAR(now)*12+MONTH(now)) - MAX(year_paid*12+month_paid) > 1
Because you don't have the day of the month of the payment, there are some borderline conditions you might miss.

Categories