I have 2 tables, ord_tbl and pay_tbl with these data:
ord_tbl
invoice | emp_id | prod_id | amount
123 | 101 | 1 | 1000
123 | 101 | 2 | 500
123 | 101 | 3 | 500
124 | 101 | 2 | 300
125 | 102 | 3 | 200
pay_tbl
invoice | new_invoice | amount
123 | 321 | 300
123 | 322 | 200
124 | 323 | 300
125 | 324 | 100
I would like the selection statement to give me this result
invoice | emp_id | orig_amt | balance | status
123 | 101 | 2000 | 1500 | unsettled
The invoice that has 0 balance will not be included anymore. This is what I tried so far...
;WITH CTE as
(SELECT ot.invoice, MAX(ot.emp_id) as emp_id, SUM(ot.amount) as origAmt FROM ord_tbl ot GROUP BY ot.invoice),
CTE2 as
(SELECT pt.invoice, SUM(pt.amountt) as payAmt FROM pay_tbl GROUP BY pt.invoice)
SELECT CTE.invoice, CTE.emp_id, CTE.origAmt, CTE.origAmt-CTE2.payAmt as bal, 'UNSETTLED' as status
FROM
CTE LEFT JOIN CTE2 ON CTE.invoice=CTE2.invoice
WHERE CTE.emp_id='101' AND CTE.origAmt-CTE2.payAmt>0 OR CTE2.patAmt IS NULL
This has been taught to me here and it works in sql server. What I need now is to have this run in ms access. I tried this code but ms access gives me an error saying "Invalid SQL statement; expected 'DELETE','INSERT', 'SELECT', or 'UPDATE'."
Can you help? Thanks.
MS ACCESS sql is poor and ACCESS doesn't know WITH instruction. I created tables (all fields int type). I rewrote query and this query works:
SELECT CTE.invoiceCTE,
CTE.emp_idCTE,
CTE.origAmtCTE,
CTE.origAmtCTE-CTE2.payAmtCTE2 as bal,
'UNSETTLED' as status
FROM
(SELECT invoice as invoiceCTE,
MAX(emp_id) as emp_idCTE,
SUM(amount) as origAmtCTE
FROM ord_tbl
GROUP BY invoice) as CTE
LEFT JOIN
( SELECT invoice as invoiceCTE2,
SUM(amount) as payAmtCTE2
FROM pay_tbl
GROUP BY invoice) as CTE2
ON CTE.invoiceCTE=CTE2.invoiceCTE2
WHERE CTE.emp_idCTE=101
AND (CTE.origAmtCTE-CTE2.payAmtCTE2>0 OR CTE2.payAmtCTE2 IS NULL)
I don't know about emp_id. If it is some kind of customer id you'd have only one per invoice_id and you'd need this SQL:
SELECT
ord_tbl.invoice,
First(ord_tbl.emp_id) AS ErsterWertvonemp_id,
Sum(ord_tbl.amount) AS origAmt,
Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]) AS bal,
"unsettled" AS status
FROM
ord_tbl LEFT JOIN pay_tbl
ON ord_tbl.invoice = pay_tbl.invoice
GROUP BY ord_tbl.invoice
HAVING (((Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]))>0));
If you want to select only the ones with emp_id=101 you'd need this:
SELECT
ord_tbl.invoice,
ord_tbl.emp_id,
Sum(ord_tbl.amount) AS origAmt,
Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]) AS bal,
"unsettled" AS status
FROM
ord_tbl LEFT JOIN pay_tbl
ON ord_tbl.invoice = pay_tbl.invoice
GROUP BY
ord_tbl.invoice,
ord_tbl.emp_id
HAVING (
((ord_tbl.emp_id)=101)
AND
((Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]))>0)
);
Related
A more generic title for this post would be
MySql Sum different columns in same table based on value of another row, group by yet another row
I have a table of employee expenses:
id | employee_id | expense_cat_id | expense_amount |
1 | 11 | 1 | 100 |
2 | 11 | 1 | 200 |
3 | 12 | 1 | 120 |
4 | 12 | 1 | 140 |
5 | 11 | 2 | 5 |
6 | 12 | 2 | 8 |`
and I want to produce a report like this:
Employee Id | Expense Cat 1 Total Amount | Expense Cat 2 Total Amount
11 | 300 | 5
12 | 260 | 8
So initially I thought I could use 2 table aliases for the same table like this:
SELECT
employee_id,
sum(expense_cat_1.expense_amount) as expense_1_total,
sum(expense_cat_2.expense_amount) as expense_2_total
FROM
expenses as expense_cat_1 where expense_cat_1.expense_cat_id=1 ,
expenses as expense_cat_2 where expense_cat_2.expense_cat_id=2
group by employee_id
but this was not correct Sql Syntax, which makes sense to me.
So I thought I could do two joins on between employee table and the expenses table:
SELECT
employees.id as employee_id,
sum(expenses_cat_1.expense_amount) as expense_1_total,
sum(expenses_cat_2.expense_amount) as expense_2_total
FROM employees
join expenses as expenses_cat_1 on employees.id = expenses_cat_1.employee_id and expenses_cat_1.expense_cat_id=1
join expenses as expenses_cat_2 on employees.id = expenses_cat_2.employee_id and expenses_cat_2.expense_cat_id=2
group by employees.id
Which comes close, but is wrong:
employee_id | expense_1_total | expense_2_total
11 | 300 | 10
12 | 260 | 16
as the expense 2 total is doubled! I think this is because the join on shows up two rows for each of the two expenses with category 1, and sums them.
I also tried a sub-query approach:
SELECT (SELECT sum(expense_amount)
FROM expenses
WHERE expense_cat_id = 1) AS sum1 ,
(SELECT sum(expense_amount)
FROM expenses
WHERE expense_cat_id = 2) AS sum2,
employee_id
FROM expenses group by employee_id
but this has the same problem as the join approach - totals for cat 2 are doubled.
How do I make the second join only include the expense_2_total once ???
I have a personal dislike of sql case statements as they seem more of a procedural language construct (and sql is declarative), but am happy to consider their use in this case - but I put the challenge out there for sql experts to solve this elegantly.
You are looking for conditional aggregation:
SELECT employee_id,
sum(case when expense_cat_id = 1 then expense_amount else 0 end) as expense_1_total,
sum(case when expense_cat_id = 2 then expense_amount else 0 end) as expense_2_total
FROM expenses e
GROUP BY employee_id;
I have two tables: invoices and items.
invoices
id | timest
items
id | invoice_id | price | qty
It is apparent an invoice may have several items - items.invoice_id = invoices.id.
I have the following query that selects all invoices with the total sum of theirs items:
SELECT id, DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
(SELECT SUM(it.price*it.quantity) FROM items AS it WHERE it.invoice_id=inv.id) as total
FROM `invoices` `inv`
This generates something like:
id| _period | total
-------------------
1 | 2014-06 | 100
4 | 2014-06 | 200
5 | 2014-07 | 660
6 | 2014-07 | 300
7 | 2014-07 | 30
9 | 2015-02 | 225
Now I want to group it by the period to have output as:
_period | qty | total_price
---------------------------
2014-06 | 2 | 300
2014-07 | 3 | 990
2015-02 | 1 | 224
I can easily do it for the quantity field as
SELECT DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
COUNT(inv.id) as qty
FROM `invoices` `inv`
GROUP BY _period
But I can't figure out how the similar thing could be done for the total_price field, which results from a subquery virtual field? Does anyone have any idea?
Thank you!
You should do this using a LEFT JOIN and GROUP BY:
SELECT DATE_FORMAT(FROM_UNIXTIME(i.time, '%Y-%m') AS _period,
COUNT(DISTINCT i.id) as num_invoices
SUM(i.price * it.quantity) as total
FROM invoices i LEFT JOIN
items it
ON it.invoice_id = i.id
GROUP BY _period
ORDER BY _period;
try this
SELECT InnerTable._period, Count(InnerTable.id) as id, Sum(InnerTable.total) as total FROM
(SELECT id, DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
(SELECT SUM(it.price*it.quantity) FROM items AS it WHERE it.invoice_id=inv.id) as total
FROM `invoices` `inv`) as InnerTable FROM GROUP BY InnerTable._period.
Making sub table from the query and then put group by on it.
I have 2 tables that I am trying to join but I am not sure how to make it the most time efficient.
Tasks Table:
nid | created_by | claimed_by | urgent
1 | 11 | 22 | 1
2 | 22 | 33 | 1
3 | 33 | 11 | 1
1 | 11 | 43 | 0
1 | 11 | 44 | 1
Employee Table:
userid | name
11 | EmployeeA
22 | EmployeeB
33 | EmployeeC
Result I am trying to get:
userid | created_count | claimed_count | urgent_count
11 | 3 | 1 | 3
22 | 1 | 1 | 2
33 | 1 | 1 | 2
created_account column will show total # of tasks created by that user.
claimed_count column will show total # of tasks claimed by that user.
urgent_count column will show total # of urgent tasks (created or claimed) by that user.
Thanks in advance!
I would start by breaking this up into pieces and then putting them back together. You can get the created_count and claimed_count using simple aggregation like this:
SELECT created_by, COUNT(*) AS created_count
FROM myTable
GROUP BY created_by;
SELECT claimed_by, COUNT(*) AS claimed_count
FROM myTable
GROUP BY claimed_by;
To get the urgent count for each employee, I would join the two tables on the condition that the employee is either the created_by or claimed_by column, and group by employee. Instead of counting, however, I would use SUM(). I am doing this because it appears each row will be either 0 or 1, so SUM() will effectively count all non-zero rows:
SELECT e.userid, SUM(t.urgent)
FROM employee e
JOIN task t ON e.userid IN (t.created_by, t.claimed_by)
GROUP BY e.userid;
Now that you have all the bits of data you need, you can use an outer join to join all of those subqueries to the employees table to get their counts. You can use the COALESCE() function to replace any null counts with 0:
SELECT e.userid, COALESCE(u.urgent_count, 0) AS urgent_count, COALESCE(crt.created_count, 0) AS created_count, COALESCE(clm.claimed_count, 0) AS claimed_count
FROM employee e
LEFT JOIN(
SELECT e.userid, SUM(t.urgent) AS urgent_count
FROM employee e
JOIN task t ON e.userid IN (t.created_by, t.claimed_by)
GROUP BY e.userid) u ON u.userid = e.userid
LEFT JOIN(
SELECT claimed_by, COUNT(*) AS claimed_count
FROM task
GROUP BY claimed_by) clm ON clm.claimed_by = e.userid
LEFT JOIN(
SELECT created_by, COUNT(*) AS created_count
FROM task
GROUP BY created_by) crt ON crt.created_by = e.userid;
Here is an SQL Fiddle example.
Update #1: query gives me syntax error on Left Join line (running the query within the left join independently works perfectly though)
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance'
FROM MyTable b1
JOIN CustomerInfoTable c on c.id = b1.company_id
#Filter for Clients of particular brand, package and active status
where c.brand_id = 2 and c.status = 2 and c.package_id = 3
LEFT JOIN
(
SELECT b2.company_id, sum(b2.debit) as 'Current_Usage'
FROM MyTable b2
WHERE year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
)
b3 on b3.company_id = b1.company_id
group by b1.company_id;
Original Post:
I keep track of debits and credits in the same table. The table has the following schema:
| company_id | timestamp | credit | debit |
| 10 | MAY-25 | 100 | 000 |
| 11 | MAY-25 | 000 | 054 |
| 10 | MAY-28 | 000 | 040 |
| 12 | JUN-01 | 100 | 000 |
| 10 | JUN-25 | 150 | 000 |
| 10 | JUN-25 | 000 | 025 |
As my result, I want to to see:
| Grouped by: company_id | Balance* | Current_Usage (in June) |
| 10 | 185 | 25 |
| 12 | 100 | 0 |
| 11 | -54 | 0 |
Balance: Calculated by (sum(credit) - sum(debits))* - timestamp does not matter
Current_Usage: Calculated by sum(debits) - but only for debits in JUN.
The problem: If I filter by JUN timestamp right away, it does not calculate the balance of all time but only the balance of any transactions in June.
How can I calculate the current usage by month but the balance on all transactions in the table. I have everything working, except that it filters only the JUN results into the current usage calculation in my code:
SELECT b.company_id, ((sum(b.credit)-sum(b.debit))/1024/1024/1024/1024) as 'BW_remaining', sum(b.debit/1024/1024/1024/1024/28*30) as 'Usage_per_month'
FROM mytable b
#How to filter this only for the current_usage calculation?
WHERE month(a.timestamp) = 'JUN' and a.credit = 0
#Group by company in order to sum all entries for balance
group by b.company_id
order by b.balance desc;
what you will need here is a join with sub query which will filter based on month.
SELECT T1.company_id,
((sum(T1.credit)-sum(T1.debit))/1024/1024/1024/1024) as 'BW_remaining',
MAX(T3.DEBIT_PER_MONTH)
FROM MYTABLE T1
LEFT JOIN
(
SELECT T2.company_id, SUM(T2.debit) T3.DEBIT_PER_MONTH
FROM MYTABLE T2
WHERE month(T2.timestamp) = 'JUN'
GROUP BY T2.company_id
)
T3 ON T1.company_id-T3.company_id
GROUP BY T1.company_id
I havn't tested the query. The point here i am trying to make is how you can join your existing query to get usage per month.
alright, thanks to #Kshitij I got it working. In case somebody else is running into the same issue, this is how I solved it:
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance',
(
SELECT sum(b2.debit)
FROM MYTABLE b2
WHERE b2.company_id = b1.company_id and year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
) AS 'Usage_June'
FROM MYTABLE b1
#Group by company in order to add sum of all zones the company is using
group by b1.company_id
order by Usage_June desc;
I have a table say :
id| AccID | Subject | Date
1 | 103 | Open HOuse 1 | 11/24/2011 9:00:00 AM
2 | 103 | Open HOuse 2 | 11/25/2011 10:00:00 AM
3 | 72 | Open House 3 | 11/26/2011 1:10:28 AM
4 | 82 | OPen House 4 | 11/27/2011 5:00:29 PM
5 | 82 | OPen House 5 | 11/22/2011 5:00:29 PM
From the above table, i need all the unique values for the Accid. But say, if there are two or more columns with the same Accid, then i need the one which has the smaller date (among the columns which have the same Accid)
So, from the above table, the o/p should be :
1
3
5
Can any1 please help me in this ? Thanks
SELECT t1.*
FROM [MyTable] t1
INNER JOIN
(
SELECT AccID, MIN(Date) Date
FROM [MyTable]
GROUP BY AccID
) t2 ON t1.AccID = t2.AccID AND t1.Date = t2.Date
More than just the AccID but...
WITH SEL
AS
(
SELECT AccID, MIN(DATE)
FROM table
GROUP BY AccID
)
SELECT table.*
FROM table
JOIN SEL ON SEL.AccID = table.AccID