How to sum up all the transactions per terminalcode - mysql

i've written up a query in sql developer however im having few problems;
The goal is to sum up all the transactions which occured on the terminal per date
i've been playing around with the count() and still no luck , watched a few videos but still nothing i get single transaction per terminal
SELECT
count(1) AS cnt,
p.terminalcode AS terminal,
trunc(p.clientdate) AS payment_date,
p.otdnum,
sum((nvl(p.clientsum,0)) + (nvl(p.penaltysum,0))) AS total_sum,
nvl(p.commissionsum,0) AS upper_commission
FROM payment_cp pcp
INNER JOIN committedpayments cp
ON cp.committedpaymentid = pcp.cp
INNER JOIN payments p
ON pcp.payment_id = p.paymentid
WHERE trunc(p.clientdate) BETWEEN :p_date_from and :p_date_to
GROUP BY p.terminalcode,
cp.pay_string,
p.clientsum,
p.commissionsum,
p.otdnum,
p.clientdate
All i get is loads of entries for terminals and broken down to single transaction, i want to have lets say terminal x 7 transaction summed up rather than see all of the 7 transactions seperately.
Any help would be appriciated

Out of the blue I would say your grouping is incorrect and your counting. If you have a unique identifier for transactions, put it into your counting like COUNT(DISTINCT myID) AS cnt. If you see more rows than you expect, check the attributes within the grouping. You probably group over a wrong attribute. My guess would be that you should remove 'pay_string', 'clientsum', 'commissionsum' and 'otdnum' from your grouping.

Related

MySQL INNER JOIN with GROUP BY and COUNT(*)

I've never been able to get my head around INNER JOINs (or any other JOIN types for that matter) so I'm struggling to work out how to use it in my specific situation. In fact, I'm not even sure if it's what I need. I've looked at other examples and read tutorials but my brain just doesn't seem to work the way needed to truly get it (or it doesn't function at all).
Here's the scenario:
I have two tables -
phone_numbers - this table has a list of phone numbers that
belong to lots of different customers. A single customer can have
multiple numbers. For simplicity's sake, we'll say the fields are
'number_id', 'customer_id', 'phone_number'.
call_history - this table has a record of every single call that one of these
numbers in the first table could have had. There's a record for
every individual call going back years. Again, for simplicity,
we'll say the relevant fields are customer_id, phone_number,
call_start_time.
What I'm trying to accomplish is to find all of the numbers that belong to a particular customer_id in the phone numbers table and use that information to search through the call_history table and find the number of calls each phone number has received, and group that by the number of calls for each number, preferably also showing zeros where a number hasn't received any calls at all.
The reason the zero calls is important is because that's the data I'm interested in. Otherwise, I could just get all the information out of the call_history table. But what I'm trying to achieve is find the numbers with no activity.
All I've been able to accomplish is run one query to get all of the numbers belonging to one customer:
SELECT customer_id, phone_number FROM phone_numbers WHERE customer_id = Y;
Then run a second query to get all phone calls for that customer_id for a set duration:
SELECT customer_id, phone_number, COUNT(*) FROM call_history WHERE customer_id = Y and call_start_time >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY) GROUP BY phone_number;
I've then had to use the data returned from both queries and use a VLOOKUP function in Excel to match number of calls for each individual number from the second query to the list of all numbers from the first query, thus leaving blanks in my "all numbers" table and identifying those numbers that had no calls for that time period.
I'm hoping there's some way to do all of this with a single query and return a table of results, listing the zero number of calls with it and eliminate the whole manual Excel bit as it's not overly efficient and prone to human error.
Without at least a workable example from you, it's not easy to re-create your situation. Anyway, INNER JOIN might not return the result as how you expected. In my short time with MySQL, I mainly use 2 types of JOIN; one is already mentioned and the other is LEFT JOIN. From what I can understand in your question, what you want to achieve can be done by using LEFT JOIN instead of INNER JOIN. I may not be the best person to explain this to you but this is how I understand it:
INNER JOIN - only return anything that match in ON clause between two (or more) tables.
LEFT JOIN - will return everything from the table on the left side of the join and return NULL if ON get no match in the table on the right side of the join .. unless you specify some WHERE condition from something on the right table.
Now, here is my query suggestion and hopefully it'll be useful for you:
SELECT A.customer_id, A.phone_number,
SUM(CASE WHEN call_start_time >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY)
THEN 1 ELSE 0 END) AS Total
FROM phone_numbers A
LEFT JOIN call_history B
ON A.customer_id=B.customer_id
GROUP BY A.customer_id,A.phone_number;
What I did here is I LEFT JOIN phone_numbers table with call_history on customer_id and I re-position the WHERE call_start_time >= .. condition into a CASE expression in the SELECT since putting it at WHERE will turn this into a normal join or inner join instead.
Here is an example fiddle : https://www.db-fiddle.com/f/hriFWqVy5RGbnsdj8i3aVG/1
For Inner join You should have to do like this way..
SELECT customer_id,phone_number FROM phone_numbers as pn,call_history as ch where pn.customer_id = ch.customer_id and call_start_time >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY) GROUP BY phone_number;
Just add table name whatever you want to join and add condition

something wrong with the result of mysql query with joins and select

Good day,
I am trying to join 3 tables for my inventory report but I am getting weird results out of it.
my query
SELECT i_inventory.xid,
count(x_transaction_details.xitem) AS occurrence,
i_inventory.xitem AS itemName,
SUM(i_items_group.or_qty) AS `openingQty`,
avg(x_transaction_details.cost) AS avg_cost,
SUM(x_transaction_details.qty) AS totalNumberSold,
SUM(i_items_group.or_qty) - SUM(x_transaction_details.qty) AS totalRemQty
FROM x_transaction_details
LEFT JOIN i_inventory ON x_transaction_details.xitem = i_inventory.xid
LEFT JOIN i_items_group ON i_inventory.xid = i_items_group.xitem
WHERE (x_transaction_details.date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
AND i_inventory.xid = 3840
GROUP BY x_transaction_details.xitem
ORDER BY occurrence DESC
This query gives me this result:
See the openingQty column, I then tried to do a simple query to verify the result,
here's my query for checking the openingQty with joining only 2 tables i_items_group table (batches are stored) and i_inventory table (item Information are stored).
SELECT i_inventory.xid,
i_inventory.xitem,
SUM(i_items_group.or_qty) AS openingQty,
i_items_group.cost
FROM i_inventory
INNER JOIN i_items_group ON i_inventory.xid = i_items_group.xitem
WHERE i_inventory.xid = 3840
AND (i_items_group.date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
my result was:
which is the correct data.
I also made a query on my x_transaction_details table also to verify if its correct or not.
heres my query:
select xitem, qty as qtySold from x_transaction_details where xitem = 3840
AND (date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
result:
Which would total to: 15-quatitySold.
I'm just confused on how did I get 3269 as a result of my query where as the true openingQty should be only 467.
I guess the problem was in my query with joins, its messing up with number of transactions then it sums it up (I really dont know though).
Can you please help me identify it, and help me come up with the correct query.
This is a common problem with multiple SUM statements in a single query. Keep in mind how SQL does aggregation: first it generates a set of data that is not aggregated, then it aggregates it. Try your query without the GROUP BY or aggregate functions, and you'll be surprised what you turn up. There aren't enough of the right details in your post for me to determine where the breakdown is, but I can guess.
It looks like you have an xitem corresponding to some kind of product, then you have joined that to both transactions and items groups. Suppose a particular xitem matches with 3 transactions and 5 item groups. You'll get 15 records from that join. And when you sum it, any SUM calculations based on fields from the transaction table will be 5x higher than you expect, and any SUM calculations from the item groups table will be 3x higher than you expect. The key symptom here is the aggregate result being a multiple of the correct value, but seemingly different multiples for different rows.
There are multiple ways to address this kind of error. Some developers like to calculate one of hte aggregates in a subquery, then do the other aggregate in the main query and group by the already correct result from the subquery. Others like to write in-line queries to do the aggregate right in the expression:
SELECT xitem, (SELECT SUM(i_items_group.or_qty) FROM i_items_group WHERE i_inventory.xid = i_items_group.xitem) AS `openingQty`
, -- select more fields
Find what approach works best for you. But if you want to see the evidence for yourself, run this query with the aggregates gone and you'll see why those SUMs are doing what they are doing:
SELECT i_inventory.xid,
x_transaction_details.xitem AS occurrence,
i_inventory.xitem AS itemName,
i_items_group.or_qty,
x_transaction_details.cost,
x_transaction_details.qty,
i_items_group.or_qty - x_transaction_details.qty AS RemainingQty
FROM x_transaction_details
LEFT JOIN i_inventory ON x_transaction_details.xitem = i_inventory.xid
LEFT JOIN i_items_group ON i_inventory.xid = i_items_group.xitem
WHERE (x_transaction_details.date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
AND i_inventory.xid = 3840
ORDER BY occurrence DESC

MySQL grouping error

I'm trying to run a query on a table to see how many unique users have a usage record in the system at a given point. I've been working with the following query, but I've yet to see a proper result.
SELECT count(distinct usageUser), divisionName
FROM records R
INNER JOIN locate L
ON L.computerID=R.usageComputerID
WHERE R.usageWhen LIKE "2012-07-08T12:%"
GROUP BY L.divisionName;
Currently the query returns 18, for each division in the joined table. Without the GROUP BY clause I get the same number of records.
EDIT:
I ran the query again, with suggestions from a comment. By removing the group by and count clause, I get this this (too big to post). This data is very poorly formatted, unfortunately it's inherited and fairly large.
It is not possible for these users to have used every lab like it's listed.
SELECT count(*) cnt, L.divisionName, R.usageUser
FROM records R
INNER JOIN locate L
ON L.computerID=R.usageComputerID
WHERE R.usageWhen LIKE "2012-07-08T12:%"
GROUP BY L.divisionName,R.usageUser;

Selecting last chronological record per customer where each customer has many records across many dates

I am trying to get the latest transaction for each member from a MySQL database where each member may have a different number of transaction records. I also have to link the transaction table to the customers table to ensure I don't get any SPECIAL ORDER records.
Here's my SQL:
Select membertransactions.maingym_id,
membertransactions.member_id,
membertransactions.action_id,
Max(membertransactions.date_time) As 'Latest Transaction Date',
membertransactions.date_time
From bd1.membertransactions
Inner Join db1.customers
On membertransactions.member_id = customers.id
Where customers.orderno <>'SPECIAL ORDER'
AND membertransactions.main_id = 1
AND Date_Format(membertransactions.date_time,'%Y%m%d') < '20121101'
Group By membertransactions.member_id, 'Latest Transaction Date'
I get a single row per customer, but it not always the chronologically latest row. I'm really stuck here and would greatly appreciate any help offered.
Thanks
Because you're using mysql, you can use a special feature of mysql to get this done simply. Here's how:
select * from (
Select
membertransactions.maingym_id,
membertransactions.member_id,
membertransactions.action_id,
membertransactions.date_time
From bd1.membertransactions
Join db1.customers On membertransactions.member_id = customers.id
Where customers.orderno <> 'SPECIAL ORDER'
AND membertransactions.main_id = 1
AND Date_Format(membertransactions.date_time,'%Y%m%d') < '20121101'
order by membertransactions.date_time desc) x
Group By member_id
I have removed the max(date) stuff altogether and the inner select gets all the records in latest-first date order, then the outer select groups by member_id. Here's the key: in mysql if you have a group by without aggregating the remaining columns you get the first row for the group.
Other databases will give a syntax error on this SQL, but in mysql it works like a charm
Also note the more readable formatting. I have never understood why people use "left align second word of each line" formatting. I wish I could find the person that first did that and have him flogged.

MySQL advanced sub query repetition

I'm writing some reasonably complex queries for reporting for an app I am developing. I could probably achieve all of the following through using higher level PHP, but obviously I would like to get it all done with MySQL which will obviously simplify things greatly.
The report I need is a typical sales report type query, which will list a list of people, and some relevant totals relating to them. The only minor difference is that this system relates to freight/haulage, so the "sales people" are actually lorry drivers, and the "sales" are individual consignments. Also, consignments are only linked/tied to their respective driver through the creation of "routes", which record who delivers/collects what on a specific day.
Naturally, I could use an INNER JOIN to get a list of each driver, with all of the consignments they have delivered/collected, and SUM the revenue made off these. The problem comes however, when I need to show both a column for total delivery revenue and collection revenue. These figures can come from a consignments table, which lists every consignment. Each consignment can have a flag (ENUM "D","C") which donates whether it is a delivery or collection. This can almost be ascertained easily through using sub queries but still, there will be a lot of repetition.
What I have so far:
SELECT pr.driver_callsign, d.first_name, d.last_name, sum(pc.revenue) AS total_revenue
FROM pallet_routes AS pr
INNER JOIN drivers AS d ON d.driver_callsign = pr.driver_callsign
INNER JOIN pallet_consignments AS pc ON pc.route_id = pr.route_id
GROUP BY pr.driver_callsign
ORDER BY d.driver_callsign ASC
This obviously returns a list of each driver, with the total amount of revenue made from all consignments they have tied to them.
What would be the most efficient way to further split this revenue SUM field up to show a SUM(revenue) WHERE type = "C" and SUM(revenue) WHERE type="D"? Subqueries? UNION?
It may also be worth mentioning that the end query will be narrowed down to a date range. So for example there will be a WHERE date BETWEEN x AND y put against the pallet_routes table.
Any advice would be greatfully received. Please do ask if you want me to elaborate more.
I don't know where your column type is, but if it's on pallet_consignments, you can try the following:
SELECT pr.driver_callsign, d.first_name, d.last_name,
SUM(IF(pc.`type` = 'C', pc.revenue, 0)) collection_revenue,
SUM(IF(pc.`type` = 'D', pc.revenue, 0)) delivery_revenue
FROM pallet_routes AS pr
INNER JOIN drivers AS d ON d.driver_callsign = pr.driver_callsign
INNER JOIN pallet_consignments AS pc ON pc.route_id = pr.route_id
GROUP BY pr.driver_callsign
ORDER BY d.driver_callsign ASC
Otherwise, please mention where the column type is.