Need Help on SQL - sql

I actually found something that I could work on regarding my problem "Need help with sql query". But I would appreciate it if I can get an answer to my specific question.
I have 2 tables one is TRANSACTIONS and one is EXPENSES.
TRANSACTION:
transaction_id
emp_id
sales_date
total_sales
And
EXPENSES:
expenses_id
emp_id
expense_date
expenses1
expenses2
total_expenses
I would like to sum all the TRANSACTION.transaction_amount AS sales_sum WHERE TRANSACTION.sales_date = #sales_date and TRANSACTION.emp_id = #emp_id ..... and then, subtract the EXPENSES.total_expenses as expenses_deducted_sales WHERE EXPENSES.emp_id = TRANSACTION.emp_id AND TRANSACTION.sales_date = EXPENSES.expense_date
PLEASE HELP.. Thank you
Ex
transaction_id emp_id sales_date total_sales
1 101 11/11/2012 300
2 101 11/11/2012 400
3 101 11/11/2012 300
expenses_id emp_id expenses_date expenses1 expenses2 total_expenses
1 101 11/11/2012 100 100 200
2 102 12/12/2012 50 50 100
3 103 10/12/2012 200 200 400
expenses_deducted_sales = (300 + 400 + 300) - 200
I've tried the code given by AHiggins and came up with these:
SELECT
CashTransactionsTbl.emp_id,
CashTransactionsTbl.trans_date,
CashTransactionsTbl.total_amt - ISNULL(ExpensesTbl.total_expenses,0) AS expenses_deducted_sales
FROM
(
SELECT
emp_id,
trans_date,
SUM(total_amt) AS sales_sum
FROM CashTransactionsTbl
GROUP BY emp_id, trans_date
) tr
LEFT JOIN
ExpensesTbl ON
tr.emp_id = ExpensesTbl.emp_id AND
tr.trans_date = ExpensesTbl.trans_date
WHERE
tr.trans_date = 2014-07-10
but no I have this error that says:
"Operand type clash: date is incompatible with int"
Please help!

You need two derived tables: One with the transaction sum per employee, one with the expenses sum per employee. Full outer join These to get all records.
select
coalesce(t.emp_id, e.emp_id) as emp_id,
coalesce(t.sum_sales, 0) as sum_sales,
coalesce(e.sum_expenses, 0) as sum_expenses,
coalesce(t.sum_sales, 0) - coalesce(e.sum_expenses, 0) as expenses_deducted_sales
from
(
select emp_id, sum(total_sales) as sum_sales
from transaction
group by emp_id
) t
full outer join
(
select emp_id, sum(total_expenses) as sum_expenses
from expense
group by emp_id
) e on e.emp_id = t.emp_id;

You need to get the aggregate data from Transactions before you match that with the data from Expenses, like so:
SELECT
tr.Emp_ID,
tr.Sales_Date,
tr.Sales_Sum - ISNULL(Expenses.Total_Expenses,0) AS Expenses_Deducted_Sales
FROM
(
SELECT
Emp_ID,
Sales_Date,
SUM(Total_Sales) Sales_Sum
FROM Transactions
) tr
LEFT JOIN
Expenses ON
tr.Emp_ID = Expenses.Emp_ID AND
tr.Sales_Date = Expenses.Expenses_Date
WHERE
tr.Sales_Date = #sales_date -- this could also go under the 'FROM Transactions' statement

This is pretty rough but something like this would work:
Select T_Sales.*,T_Sales.totalsales-totalexpesnses 'Expenses_deducted_sales'
from (
select t.emp_id,sales_date,SUM(totalsales) 'totalsales'
from #transaction t
group by t.emp_id,sales_date
) T_Sales
left join #expenses e
on T_Sales.emp_id = e.emp_id
and T_Sales.sales_date = e.expenses_date
where sales_date = #sales_date
ps. Apologies for spelling - quick work.

Related

What is wrong with my SQL query SUM group-by

Hello i have a sql query and it does not count my one row. which is called Spend, you can see it in the fiddle. what is wrong with my code?
I just need basic table
Month ID GOT SPEND
1 1 100 50
2 1 500 200
1 2 200 50
I have created the fiddle http://sqlfiddle.com/#!9/3623b1/2
Could you please help me?
Here is the query:
select
keliones_lapas.Vairuot_Id,
MONTH(keliones_lapas.Data_darbo),
sum(keliones_lapas.uzdarbis) as Got,
coalesce(Suma, 0) AS Spend,
(sum(keliones_lapas.uzdarbis) - coalesce(Suma, 0)) Total
from keliones_lapas
left join (
select Vairuotas,
MONTH(Data_islaidu) as Data_islaidu,
sum(Suma) as Suma
from islaidos
group by Vairuotas, MONTH(Data_islaidu)) islaidos
on keliones_lapas.Vairuot_Id = islaidos.Vairuotas
and MONTH(keliones_lapas.Data_darbo) = MONTH(islaidos.Data_islaidu)
group by keliones_lapas.Vairuot_Id, MONTH(keliones_lapas.Data_darbo), Suma
order by keliones_lapas.Vairuot_Id, MONTH(keliones_lapas.Data_darbo);
TRY THIS: You are taking already month in your subquery then again using MONTH to retrieve from month in the join so it's returning NULL and not matching with any month of keliones_lapas
SELECT
keliones_lapas.Vairuot_Id,
MONTH(keliones_lapas.Data_darbo),
SUM(keliones_lapas.uzdarbis) AS Got,
COALESCE(Suma, 0) AS Spend,
(SUM(keliones_lapas.uzdarbis) - COALESCE(Suma, 0)) Total
FROM keliones_lapas
LEFT JOIN (
SELECT Vairuotas,
MONTH(Data_islaidu) AS Data_islaidu, --It's already in MONTH
SUM(Suma) AS Suma
FROM islaidos
GROUP BY Vairuotas, MONTH(Data_islaidu)) islaidos
ON keliones_lapas.Vairuot_Id = islaidos.Vairuotas
AND MONTH(keliones_lapas.Data_darbo) = Data_islaidu --No need to use MONTH or `vice versa`
GROUP BY keliones_lapas.Vairuot_Id, MONTH(keliones_lapas.Data_darbo), Suma
ORDER BY keliones_lapas.Vairuot_Id, MONTH(keliones_lapas.Data_darbo)

Getting rid of grouping field

Is there a safe way to not have to group by a field when using an aggregate in another field? Here is my example
SELECT
C.CustomerName
,D.INDUSTRY_CODE
,CASE WHEN D.INDUSTRY_CODE IN ('003','004','005','006','007','008','009','010','017','029')
THEN 'PM'
WHEN UPPER(CustomerName) = 'ULINE INC'
THEN 'ULINE'
ELSE 'DR'
END AS BU
,ISNULL((SELECT SUM(GrossAmount)
where CONVERT(date,convert(char(8),InvoiceDateID )) between DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) - 1, 0) and DATEADD(year, -1, GETDATE())),0) [PREVIOUS YEAR GROSS]
FROM factMargins A
LEFT OUTER JOIN dimDate B ON A.InvoiceDateID = B.DateId
LEFT OUTER JOIN dimCustomer C ON A.CustomerID = C.CustomerId
LEFT OUTER JOIN CRCDATA.DBO.CU10 D ON D.CUST_NUMB = C.CustomerNumber
GROUP BY
C.CustomerName,D.INDUSTRY_CODE
,A.InvoiceDateID
order by CustomerName
before grouping I was only getting 984 rows but after grouping by the A.InvoiceDateId field I am getting over 11k rows. The rows blow up since there are multiple invoices per customer. Min and Max wont work since then it will pull data incorrectly. Would it be best to let my application (crystal) get rid of the extra lines? Usually I like to have my base data be as close as possible to how the report will layout if possible.
Try moving the reference to InvoiceDateID to within an aggregate function, rather than within a selected subquery's WHERE clause.
In Oracle, here's an example:
with TheData as (
select 'A' customerID, 25 AMOUNT , trunc(sysdate) THEDATE from dual union
select 'B' customerID, 35 AMOUNT , trunc(sysdate-1) THEDATE from dual union
select 'A' customerID, 45 AMOUNT , trunc(sysdate-2) THEDATE from dual union
select 'A' customerID, 11000 AMOUNT , trunc(sysdate-3) THEDATE from dual union
select 'B' customerID, 12000 AMOUNT , trunc(sysdate-4) THEDATE from dual union
select 'A' customerID, 15000 AMOUNT , trunc(sysdate-5) THEDATE from dual)
select
CustomerID,
sum(amount) as "AllRevenue"
sum(case when thedate<sysdate-3 then amount else 0 end) as "OlderRevenue",
from thedata
group by customerID;
Output:
CustomerID | AllRevenue | OlderRevenue
A | 26070 | 26000
B | 12035 | 12000
This says:
For each customerID
I want the sum of all amounts
and I want the sum of amounts earlier than 3 days ago

Trouble running a complex query in sql?

I am pretty new to SQL Server and just started playing with it. I am trying to create a table that shows attendance percentage by department.
So first i run this query:
SELECT CrewDesc, COUNT(*)
FROM database.emp
INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
This gives a table like this:
Accounting 10
Marketing 5
Economics 20
Engineering 5
Machinery 5
Tech Support 10
Then i run another query:
SELECT DeptDescription, COUNT(*)
FROM database.Attendee
GROUP BY DeptDescription
This gives me the result of all the people that have attended meeting something like
Accounting 8
Marketing 5
Economics 15
Engineering 10
Tech Support 8
Then I get the current week in the year by SELECT Datepart(ww, GetDate()) as CurrentWeek To make this example easy lets assume this will be week "2".
Now the way i was going to create this was a table for each step but that seems like waste. Is there a way we can combine to tables in a query? So in the end result i would like a table like this
Total# Attd Week (Total*Week) Attd/(Total*week)%
Accounting 10 8 2 20 8/20
Marketing 5 5 2 10 5/10
Economics 20 15 2 40 15/40
Engineering 5 10 2 10 10/10
Machinery 5 NULL 2 10 0/10
Tech Support 10 8 2 20 8/20
Ok, note that my recommendation below is based on your exact existing queries - there are certainly other ways to construct this that may be more performant, but functionally this should work for your requirement. Also, it illustrates the key features of different join types that happen to be relevant for your request, as well as inline views (aka nested queries), which are a super-powerful technique in the SQL language as a whole.
select t1.CrewDesc, t1.Total, t2.Attd, t3.Week,
(t1.Total*t3.Week) as Total_x_Week,
case when isnull(t1.Total*t3.Week, 0) = 0 then 0 else isnull(t2.Attd, 0) / isnull(t1.Total*t3.Week, 0) end as PercentageAttd
from (
SELECT CrewDesc, COUNT(*) AS Total
FROM database.emp INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
) t1
left outer join /* left outer to keep all rows from t1 */ (
SELECT DeptDescription, COUNT(*) AS Attd
FROM database.Attendee GROUP BY DeptDescription
) t2
on t1.CrewDesc = t2.DeptDescription
cross join /* useful when adding a scalar value to all rows */ (
SELECT Datepart(ww, GetDate()) as Week
) t3
order by t1.CrewDesc
Good luck!
Try something like this
SELECT COALESCE(a.crewdesc,b.deptdescription),
a.total,
b.attd,
Datepart(ww, Getdate()) AS week,
total * Datepart(ww, Getdate()),
b.attd/(a.total*Datepart(ww, Getdate()))
FROM (query 1) a
FULL OUTER JOIN (query 2) b
ON a.crewdesc = b.deptdescription
WITH Total AS ( SELECT CrewDesc, COUNT(*) AS [Count]
FROM database.emp
INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
),
Attd AS ( SELECT DeptDescription, COUNT(*) AS [Count]
FROM database.Attendee
GROUP BY DeptDescription
)
SELECT COALESCE(CrewDesc,DeptDescription) AS [Dept],
Total.[Count] AS [Total#],Attd.[Count] AS [Attd],
Total.[Count] * Datepart(ww, GetDate()) AS [(Total*Week)],
CAST(Attd.[Count] AS VARCHAR(10))+'/'+ CAST((Total.[Count] * Datepart(ww, GetDate()))AS VARCHAR(10)) AS [Attd/(Total*week)%]
FROM Total INNER JOIN Attd ON Total.CrewDesc = Attd.DeptDescription
I'm assuming your queries are correct -- you give no real information about your model so I've no way to know. They look wrong since the same data is called CrewDesc in one table and Dept in another. Also the join sim1 = sim2 seems very strange to me. In any case given the queries you posted this will work.
With TAttend as
(
SELECT CrewDesc, COUNT(*) as TotalNum
FROM database.emp
INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
), Attend as
(
SELECT DeptDescription, COUNT(*) as Attd
FROM database.Attendee
GROUP BY DeptDescription
)
SELECT CrewDesc as Dept, TotalNum, ISNULL(Attd, 0) as Attd ,Datepart(ww, GetDate()) as Week,
CASE WHEN ISNULL(Attd, 0) > 0 THEN 0
ELSE ISNULL(Attd, 0) / (TotalNum * Datepart(ww, GetDate()) ) END AS Percent
FROM TAttend
LEFT JOIN Attend on CrewDesc = DeptDescription

Need all Sales Reps on one Line

Below I have the following SQL Statement:
WITH SalesDetail as (
SELECT
PostAR.TxDate
,PostAR.AccountLink
,PostST.AccountLink AS StkLnk
,PostST.Quantity AS QtySold
,PostST.cAuditNumber
,(PostST.Credit-PostST.Debit)-(PostST.Quantity*PostST.Cost) AS Profit
,(((PostST.Credit-PostST.Debit)-(PostST.Quantity*PostST.Cost)))/((((PostST.Credit-PostST.Debit))))*100 AS GrossProfitPercent
,(PostST.Quantity*PostST.Cost) AS Cost
,(PostST.Credit-PostST.Debit) AS TotSales
,(((PostST.Credit-PostST.Debit)-(PostST.Quantity*PostST.Cost))) / ((((PostST.Quantity*PostST.Cost)+(0.00000000000001))))*100 AS MarkUpPercent
,concat(StkItem.Code, ' - ' ,StkItem.Description_1) AS StkItemCode
,SalesRep.Code AS RepCode
,SalesRep.Name AS RepName
,Client.Account CustID
,Client.Name AS CustName
,CASE
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) > 0 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 25 THEN 2
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 25 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 35 THEN 2.5
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 35 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 45 THEN 3
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 45 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 55 THEN 3.5
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 55 THEN 4
ELSE 0
END AS CommPayablePercent
FROM PostAR
INNER JOIN PostST
ON PostST.cAuditNumber = PostAR.cAuditNumber
INNER JOIN StkItem
ON StkItem.StockLink = PostST.AccountLink
INNER JOIN SalesRep
ON SalesRep.idSalesRep = PostAR.RepID
INNER JOIN Client
ON Client.DCLink = PostAR.AccountLink
)
SELECT SalesDetail.RepName
, (((SalesDetail.CommPayablePercent)/100)) * ((SalesDetail.TotSales)) As RepTotComm
, SUM(SalesDetail.TotSales) AS TotalSales
FROM SalesDetail
GROUP BY SalesDetail.RepName, SalesDetail.TotSales, SalesDetail.CommPayablePercent
ORDER BY SalesDetail.RepName
I then get the following result:
As you can see, it is multipling the TotSales by my already determained CASE formulala. That is fine. However, I do not want the reps all on a each line. I want just the rep name and then the total commission payable.
Eg:
GRAY MEIRING - $5000 - $6000
and not:
GRAY MEIRING
GRAY MEIRING
GRAY MEIRING etc etc...
Is the issue coming from my SUM function or perhaps my GROUP BY function?
Many thanks! :)
You should use GROUP BY SalesDetail.RepName only, to achieve It, you can add subquery, try something like that:
................
SELECT RepName,
SUM(RepTotComm),
SUM(TotalSales)
FROM (
SELECT SalesDetail.RepName
, (((SalesDetail.CommPayablePercent)/100)) * ((SalesDetail.TotSales)) As RepTotComm
, SUM(SalesDetail.TotSales) AS TotalSales
FROM SalesDetail
GROUP BY SalesDetail.RepName, SalesDetail.TotSales, SalesDetail.CommPayablePercent
) x
GROUP BY RepName
ORDER BY RepName

Using a column in sql join without adding it to group by clause

My actual table structures are much more complex but following are two simplified table definitions:
Table invoice
CREATE TABLE invoice (
id integer NOT NULL,
create_datetime timestamp with time zone NOT NULL,
total numeric(22,10) NOT NULL
);
id create_datetime total
----------------------------
100 2014-05-08 1000
Table payment_invoice
CREATE TABLE payment_invoice (
invoice_id integer,
amount numeric(22,10)
);
invoice_id amount
-------------------
100 100
100 200
100 150
I want to select the data by joining above 2 tables and selected data should look like:-
month total_invoice_count outstanding_balance
05/2014 1 550
The query I am using:
select
to_char(date_trunc('month', i.create_datetime), 'MM/YYYY') as month,
count(i.id) as total_invoice_count,
(sum(i.total) - sum(pi.amount)) as outstanding_balance
from invoice i
join payment_invoice pi on i.id=pi.invoice_id
group by date_trunc('month', i.create_datetime)
order by date_trunc('month', i.create_datetime);
Above query is giving me incorrect results as sum(i.total) - sum(pi.amount) returns (1000 + 1000 + 1000) - (100 + 200 + 150) = 2550.
I want it to return (1000) - (100 + 200 + 150) = 550
And I cannot change it to i.total - sum(pi.amount), because then I am forced to add i.total column to group by clause and that I don't want to do.
You need a single row per invoice, so aggregate payment_invoice first - best before you join.
When the whole table is selected, it's typically fastest to aggregate first and join later:
SELECT to_char(date_trunc('month', i.create_datetime), 'MM/YYYY') AS month
, count(*) AS total_invoice_count
, (sum(i.total) - COALESCE(sum(pi.paid), 0)) AS outstanding_balance
FROM invoice i
LEFT JOIN (
SELECT invoice_id AS id, sum(amount) AS paid
FROM payment_invoice pi
GROUP BY 1
) pi USING (id)
GROUP BY date_trunc('month', i.create_datetime)
ORDER BY date_trunc('month', i.create_datetime);
LEFT JOIN is essential here. You do not want to loose invoices that have no corresponding rows in payment_invoice (yet), which would happen with a plain JOIN.
Accordingly, use COALESCE() for the sum of payments, which might be NULL.
SQL Fiddle with improved test case.
Do the aggregation in two steps. First aggregate to a single line per invoice, then to a single line per month:
select
to_char(date_trunc('month', t.create_datetime), 'MM/YYYY') as month,
count(*) as total_invoice_count,
(sum(t.total) - sum(t.amount)) as outstanding_balance
from (
select i.create_datetime, i.total, sum(pi.amount) amount
from invoice i
join payment_invoice pi on i.id=pi.invoice_id
group by i.id, i.total
) t
group by date_trunc('month', t.create_datetime)
order by date_trunc('month', t.create_datetime);
See sqlFiddle
SELECT TO_CHAR(invoice.create_datetime, 'MM/YYYY') as month,
COUNT(invoice.create_datetime) as total_invoice_count,
invoice.total - payments.sum_amount as outstanding_balance
FROM invoice
JOIN
(
SELECT invoice_id, SUM(amount) AS sum_amount
FROM payment_invoice
GROUP BY invoice_id
) payments
ON invoice.id = payments.invoice_id
GROUP BY TO_CHAR(invoice.create_datetime, 'MM/YYYY'),
invoice.total - payments.sum_amount