Multiple Periodic Charges within a billing cycle - mysql

Each department is supposed to have only one statement per monthly billing cycle.

My goal is to figure out how many departments have been hit with more than one billing statement (having a value greater than $0.00) within the same billing cycle.  

CONTEXT: 
My current query is set to check only departments that are supposed to be billed monthly.
Department table has a one-to-many relationship with Statement table (a department is expected to have one or more statements)
Statement table has a one-to-many relationship with Trans table (a statement is expected to have one or more transactions)
Each billing statement has its own statement_close_date
c.type=‘periodic’ refers to a bill that only occurs once per billing cycle
d.period=1 represents accounts that are billed monthly
s.status=‘closed’ represents only closed statements
d.exp_date represents billing expiration date
v.status=‘active’ and d.status=‘active’ are meant to ensure that only active departments are being queried.
I also tried searching between specific expire dates on a per account basis.

The problem with my query is that it outputs the total number of billing statement_close_dates with a value greater than $0.00, instead of only checking for multiple occurrences within a billing cycle. 

How can this query be modified to only output departments with more than one instance of a bill consisting of a periodic type charge greater than $0.00 within each department’s billing cycle?  

QUERY:
SELECT s.department_id, s.statement_id, COUNT(s.statement_close_date) AS sd,
t.trans_id, from_unixtime(s.statement_close_date)
FROM statement s
INNER JOIN trans t
ON t.statement_id=s.statement_id
INNER JOIN cde c
ON t.cde=c.cde
INNER JOIN department d
ON s.department_id=d.department_id
WHERE from_unixtime(s.statement_close_date) BETWEEN
DATE_SUB(from_unixtime(d.exp_date), INTERVAL 1 MONTH) AND
from_unixtime(d.exp_date)  
AND d.period=‘1’
AND s.status='closed'
AND t.dollars>0
AND c.type='periodic'
GROUP BY s.statement_id DESC
HAVING sd>1
SAMPLE OUTPUT:
department_id statement_id sd trans_id statement_close_date
1719712 9351464 3 98403043 2018-09-24
1719709 9351463 2 98403026 2018-09-24
1719708 9351462 2 98403010 2018-09-24
1719665 9351457 3 97374764 2018-09-24

Related

Get number of in time deliveries according to specific customer hour in SQL

I've 2 SQL tables:
The first is called LIVRAISON and stores all deliveries. It especially contains the customer's number (NumCptClient), date and time of the delivery (heureLiv, DateLiv) and the town name where the customer has been delivered (nomVille).
The second is called IMPERATIF that modelize a special service to clients wanting to be delivered before a given hour. That special service stands by a customer's number, a town name, the maximal hour when the customer must be delivered (heureImp) and start/end date of that premium option (dateDebImp, dateFinImp) : a delivery enters in the special service field when it matchs an IMPERATIF row by a NumCptClient AND nomVille combination and that its date is in the date range of that row (a customer, although having special service's orders, can be delivered in a town not concerned and vice versa: that kind of deliveries musn't be taken in account here).
I need to compute by a single and fast SQL query the rate between the number of deliveries that satisfied this special service (heureLiv <= heureImp) and the total number of deliveries for each couple of customer AND town concerned by this premium option.
I'd tailored that request that gives me all needed info except the rate:
SELECT NumCptCli, nomVille, heureImp, COUNT(*) AS TotalLivs
FROM LIVRAISON
NATURAL JOIN IMPERATIF
GROUP BY NumCptCli, nomVille
Then, the question is fondamentally, how to change that query so as to add a column with the corresponding rate, that is livsAlheure column below, and without display special service's couples that haven't any corresponding delivery registered yet?
NumCptCli |nomVille |heureImp|TotalLivs |livsAlheure
----------|--------------------|--------|----------|-----------
12345678 |PARIS |07:30 |311 |80.56
87654321 |BREST |15:30 |314 |95.2
...

SQL query to show updated account balances

I have two tables, [Party] and [Invoice], in an Access database. I want to summarize all party balances. Here is my query so far:
select
Party.AccountCode,
Party.AccountDescription,
OpeningBalance+sum(invoiceAmount) as balance,
invoiceDate
from Party,Inovoice
where party.accountCode=Inovice.AccountCode
and invoiceDate>=01-01-2013
and invoiceDate<=30-06-2013
group by
Party.AccountCode,
Party.AccountDescription,
invoiceDate
This query returns the balance for only the two parties that appear in the [Invoice] table: TOM and JHONS. I want to display the balance for all 4 parties:
Use two queries. The first to calculate the total invoice amount and the second for the party balances
qrySumInvoiceAmounts:
SELECT
AccountCode
sum(invoiceAmount) as InvoiceBalance,
FROM Invoice
group by
AccountCode,
WHERE invoiceDate>= #01-01-2013#
and invoiceDate<= #30-06-2013#
qryPartyBalance:
SELECT
Party.AccountCode,
Party.AccountDescription,
OpeningBalance + InvoiceBalance,
from Party LEFT JOIN qrySumInvoiceAmounts
ON party.accountCode=qrySumInvoiceAmounts.AccountCode

MySQL - The most occuring for the specific day?

I'm stuck on this problem.
Basically I need to find out for each department how to figure out which days had the most sales made in them. The results display the department number and the date of the day and a department number can appear several times in the results if there were several days that have equally made the most sales.
This is what I have so far:
SELECT departmentNo, sDate FROM Department
HAVING MAX(sDate)
ORDER BY departmentNo, sDate;
I tried using the max function to find which dates occurred most. But it only returns one row of values. To clarify more, the dates that has the most sales should appear with the corresponding column called departmentNo. Also, if two dates for department A has equal amount of most sales then department A would appear twice with both dates showing too.
NOTE: only dates with the most sales should appear and the departmentNo.
I've started mySQL for few weeks now but still struggling to grasp the likes of subqueries and store functions. But i'll learn from experiences. Thank you in advance.
UPDATED:
Results I should get:
DepartmentNo Column 1: 1 | Date Column 2: 15/08/2000
DepartmentNo Column 1: 2 | Date Column 2: 01/10/2012
DepartmentNo Column 1: 3 | Date Column 2: 01/06/1999
DepartmentNo Column 1: 4 | Date Column 2: 08/03/2002
DepartmentNo Column 1: nth | Date Column 2: nth date
These are the data:
INSERT INTO Department VALUES ('1','tv','2012-05-20','13:20:01','19:40:23','2');
INSERT INTO Department VALUES ('2','radio','2012-07-22','09:32:23','14:18:51','4');
INSERT INTO Department VALUES ('3','tv','2012-09-14','15:15:43','23:45:38','3');
INSERT INTO Department VALUES ('2','tv','2012-06-18','06:20:29','09:57:37','1');
INSERT INTO Department VALUES ('1','radio','2012-06-18','11:34:07','15:41:09','2');
INSERT INTO Department VALUES ('2','batteries','2012-06-18','16:20:01','23:40:23','3');
INSERT INTO Department VALUES ('2','remote','2012-06-18','13:20:41','19:40:23','4');
INSERT INTO Department VALUES ('1','computer','2012-06-18','13:20:54','19:40:23','4');
INSERT INTO Department VALUES ('2','dishwasher','2011-06-18','13:20:23','19:40:23','4');
INSERT INTO Department VALUES ('3','lawnmower','2011-06-18','13:20:57','20:40:23','4');
INSERT INTO Department VALUES ('3','lawnmower','2011-06-18','11:20:57','20:40:23','4');
INSERT INTO Department VALUES ('1','mobile','2012-05-18','13:20:31','19:40:23','4');
INSERT INTO Department VALUES ('1','mouse','2012-05-18','13:20:34','19:40:23','4');
INSERT INTO Department VALUES ('1','radio','2012-05-18','13:20:12','19:40:23','4');
INSERT INTO Department VALUES ('2','lawnmowerphones','2012-05-18','13:20:54','19:40:23','4');
INSERT INTO Department VALUES ('2','tv','2012-05-12','06:20:29','09:57:37','1');
INSERT INTO Department VALUES ('2','radio','2011-05-23','11:34:07','15:41:09','2');
INSERT INTO Department VALUES ('1','batteries','2011-05-21','16:20:01','23:40:23','3');
INSERT INTO Department VALUES ('2','remote','2011-05-01','13:20:41','19:40:23','4');
INSERT INTO Department VALUES ('3','mobile','2011-05-09','13:20:31','19:40:23','4');
For department1 the date 2012-05-18 would appear because that date occurred the most. And for every department, it should only show the one with the most sales, and if same amount of sales appears on the same date then both will appear, e.g. Department 1 will appear twice with both the dates of max sales.
I've tested the following query based on the table and two columns you've provided along with sample data. So, let me describe it for you. The inner-most "PREQUERY" is doing a count by department and date. The results of this will be pre-ordered by Department first, THEN the highest count in DESCENDING ORDER (so highest sales count is listed FIRST), it doesn't matter what date the count happened.
Next, by utilizing MySQL #variables, I'm pre-declaring two to be used in the query. #variables are like inline programming with MySQL. They can be declared once and then changed as applied to each record being processed. So, I'm defaulting to a bogus department value and a zero sales count.
Now, I'm grabbing the results of the PreQuery (Dept, #Sales and Date), but now, adding a test. If it is the FIRST ENTRY for a given department, use that record's "NumberOfSales" and put into the #maxSales variable and store as a final column name "MaxSaleCnt". The next column name uses the #lastDept and is set to whatever the current record's Department # is. So it can be compared to the next record.
If the next record is the same department, then it just keeps whatever the #maxSales value was from the previous, thus keeping the same first count(*) result for ALL entries on each respective department.
Now, the closure. I've added a HAVING clause (not a WHERE as that restricts what records get tested, but HAVING processes AFTER the records are part of the PROCESSED set. So now, it would have all 5 columns. I am saying ONLY KEEP those records where the final NumberOfSales for the record MATCHES the MaxSaleCnt for the department. If one, two or more dates, no problem it returns them all per respective department.
So, one department could have 5 dates with 10 sales each, and another department has 2 dates with only 3 sales each, and another with only 1 date with 6 sales.
select
Final.DepartmentNo,
Final.NumberOfSales,
Final.sDate
from
(select
PreQuery.DepartmentNo,
PreQuery.NumberOfSales,
PreQuery.sDate,
#maxSales := if( PreQuery.DepartmentNo = #lastDept, #maxSales, PreQuery.NumberOfSales ) MaxSaleCnt,
#lastDept := PreQuery.DepartmentNo
from
( select
D.DepartmentNo,
D.sDate,
count(*) as NumberOfSales
from
Department D
group by
D.DepartmentNo,
D.sDate
order by
D.DepartmentNo,
NumberOfSales DESC ) PreQuery,
( select #lastDept := '~',
#maxSales := 0 ) sqlvars
having
NumberOfSales = MaxSaleCnt ) Final
To clarify the "#" and "~" per you final comment. The "#" indicates a local variable to the program (or in this case and in-line sql variable) that can be used in the query. The '~' is nothing more than a simple string that probability would never exist that of any of your departments, so when it is compared to the first qualified record, does an IF( '~' = YourFirstDepartmentNumber, then use this answer, otherwise use this answer).
Now, how do the above work. Lets say the following is the results of your data returned by the inner-most query, grouped and ordered by the most sales at the top going down... SLIGHTLY altered from your data, lets just assume the following to simulate multiple dates on Dept 2 that have the same sales quantity...
Row# DeptNo Sales Date # Sales
1 1 2012-05-18 3
2 1 2012-06-18 2
3 1 2012-05-20 1
4 2 2012-06-18 4
5 2 2011-05-23 4
6 2 2012-05-18 2
7 2 2012-05-12 1
8 3 2011-06-18 2
9 3 2012-09-14 1
Keep track of the actual rows. The innermost query that finishes as alias "PreQuery" returns all the rows in the order you see here. Then, that is joined (implied) with the declarations of the # sqlvariables (special to MySQL, other sql engines dont do this) and starts their values with the lastDept = '~' and the maxSales = 0 (via assignment with #someVariable := result of this side ).
Now, think of the above being handled as a
DO WHILE WE HAVE RECORDS LEFT
Get the department #, Number of Sales and sDate from the record.
IF the PreQuery Record's Department # = whatever is in the #lastDept
set MaxSales = whatever is ALREADY established as max sales for this dept
This basically keeps the MaxSales the same value for ALL in the same Dept #
ELSE
set MaxSales = the # of sales since this is a new department number and is the highest count
END IF
NOW, set #lastDept = the department you just processed to it
can be compared when you get to the next record.
Skip to the next record to be processed and go back to the start of this loop
END DO WHILE LOOP
Now, the reason you need to have the #MaxSales and THEN the #LastDept as returned columns is they must be computed for each record to be used to compare to the NEXT record. This technique can be used for MANY application purposes. If you click on my name, look at my tags and click on the MySQL tag, it will show you the many MySQL answers I've responded to. Many of them do utilize # sqlvariables. In addition, there are many other people who are very good at working queries, so dont just look in one place. As for any question, if you find a good answer that you find helpful, even if you didn't post the question, clicking on an up-arrow next to the answer helps others indicate what really helped them understand and get resolution to questions -- again, even if its not your question. Good luck on your MySQL growth.
I think this can be achieved with a single query, but my experiences for similar functionality have involved either WITH (as defined in SQL'99) using either Oracle or MSSQL.
The best (only?) way to approach a problem like this is to break in into smaller components. (I don't think your provided statement provides all columns, so I'm going to have to make a few assumptions.)
First, how many sales were made for each day for each group:
SELECT department, COUNT(1) AS dept_count, sale_date
FROM orders
GROUP BY department, sale_date
Next, what's the most sales for each department
SELECT tmp.department, MAX(tmp.dept_count)
FROM (
SELECT department, COUNT(1) AS dept_count
FROM orders
GROUP BY department
) AS tmp
GROUP BY tmp.department
Finally, putting the two together:
SELECT a.department, a.dept_count, b.sale_date
FROM (
SELECT tmp.department, MAX(tmp.dept_count) AS max_dept_count
FROM (
SELECT department, COUNT(1) AS dept_count
FROM orders
GROUP BY department
) AS tmp
GROUP BY tmp.department
) AS a
JOIN (
SELECT department, COUNT(1) AS dept_count, sale_date
FROM orders
GROUP BY department, sale_date
) AS b
ON a.department = b.department
AND a.max_dept_count = b.dept_count

MySQL reporting query

I have the following db schema (i'm only mentioning the columns for each table necessary for the query in mind):
bills
-------
id
amount (decimal)
collection_case_id
collection_case
------------------
id
payments
----------
id
bill_id
amount (decimal)
type (char(2)) - "CH" stands for check payment, field used for polymorphism
check_payments
---------------
payment_id
For a set of collection cases, I need to get the total interest earned from check payments.
I am currently doing these calculations in memory after retrieving all the bill records for my set of collection case criteria. For each bill I simply add the sum of checks received - bill amount if sum of checks received is greater than bill amount.
for instance my total received query looks like this (collection cases 1 & 2):
select sum(payment.amount) as received
from bills bill
cross join payments payment inner join check_payments checkpayment
on
payment.id=checkpayment.payment_id
where payment.type='CH'
and payment.bill_id=bill.id
and (bill.collection_case_id in (1 , 2))
Not really sure if this is what you meant.
select IF(sum(payment.amount) > bill.amount, sum(payment.amount)-bill.amount, 0) as interest
from bills bill
cross join payments payment inner join check_payments checkpayment
on
payment.id=checkpayment.payment_id
where payment.type='CH'
and payment.bill_id=bill.id
and (bill.collection_case_id in (1 , 2))

without losing old fees payment in MySQL

i am creating a student management system, i have 3 tables, student, fees, student_fee, the fee table contains the amount of fees and the student_fee contains reference to student.studentid and fee.feeid, so that whenever a student paid their fees, the studentid, feeid and paid_date will be insert into the student_fee table. Fees can increase the next year, how can i still keep the old records of fees payment without losing and causing any problem to the account
Instead of doing an entire history table separately, just add a column into the student_fee_paid table for the amount of the payment... so you can still query from it directly for the entire history of a student and it will have the historical values all in one... ex:
Student Fee_ID DatePaid FeeAmount
X 1 1/1/2009 $25
X 1 1/1/2010 $25
X 1 1/1/2011 $30
X 1 1/1/2012 $35
Otherwise it will just grow to a larger task... If you have 30 different fees, and the fee schedule amount changes for some but not all, what then... You can keep your "Fee" table to reflect whatever the "Current" fee amount is, but as soon as its paid, stamp that amount immediately.... if rates change mid-year, yet another trouble / history consideration... don't worry about the otherwise minimal amount of data storage this will increase.
Create a history of fee payment table. StudentID, FeeID, DatePaid, AmountPaid
or Effectively Date your Fee table.
Copy the table fees and student_fee for archive purpose.
You can use the SELECT INTO command.
http://www.w3schools.com/sql/sql_select_into.asp