I'm trying to group sales data based on a sellers' name. The name is available in another table. My tables look like this:
InvoiceRow:
+-----------+----------+-----+----------+
| InvoiceNr | Title | Row | Amount |
+-----------+----------+-----+----------+
| 1 | Chair | 1 | 2000.00 |
| 2 | Sofa | 1 | 1500.00 |
| 2 | Cushion | 2 | 2000.00 |
| 3 | Lamp | 1 | 6500.00 |
| 4 | Table | 1 | -500.00 |
+-----------+----------+-----+----------+
InvoiceHead:
+-----------+----------+------------+
| InvoiceNr | Seller | Date |
+-----------+----------+------------+
| 1 | Adam | 2016-01-01 |
| 2 | Lisa | 2016-01-04 |
| 3 | Adam | 2016-01-08 |
| 4 | Carl | 2016-01-17 |
+-----------+----------+------------+
The query that I'm working with currently looks like this:
SELECT SUM(Amount)
FROM InvoiceRow
WHERE InvoiceNr IN (
SELECT InvoiceNr
FROM InvoiceHead
WHERE Date >= '2016-01-01' AND Date < '2016-02-01'
)
This works and will sum the values of all rows of all invoices (total sales) in the month of january.
What I want to do is a sales summary grouped by each sellers' name. Something like this:
+----------+------------+
| Seller | Amount |
+----------+------------+
| Adam | 8500.00 |
| Lisa | 3500.00 |
| Carl | -500.00 |
+----------+------------+
And after that maybe even grouped by month (but that's not part of this question, I'm hoping to be able to figured that out if I solve this).
I've tried all kinds of joins but I end up with a lot of duplicates, and I'm not sure how to SUM and group at the same time. Does anyone know how to do this?
Try This
SELECT seller, SUM(amount) FROM InvoiceRow
JOIN InvoiceHead
ON InvoiceRow.InvoiceNr = InvoiceHead.InvoiceNr
GROUP BY InvoiceHead.seller;
OR If you want to between two date. Try This
SELECT seller, SUM(amount) FROM InvoiceRow
JOIN InvoiceHead
ON InvoiceRow.InvoiceNr = InvoiceHead.InvoiceNr
WHERE InvoiceHead.Date >= '2016-01-01' AND InvoiceHead.Date < '2016-02-01'
GROUP BY InvoiceHead.seller;
You just need to join the tables, filter result by date as you need and then make grouping:
select
H.Seller,
sum(R.Amount) as Amount
from InvoiceHead as H
left outer join InvoiceRow as R on R.InvoiceNr = H.InvoiceNr
where H. Date >= '2016-01-01' AND H.Date < '2016-02-01'
group by H.Seller
SELECT t.seller,sum(s.amount)
FROM invoiceRow s join InvoiceHead t
ON s.invoiceNr = t.invoiceNr
group by t.seller
You should just sum them up. If date range is necessary, you can add a where clause after the ON clause and filter you dates like this:
SELECT t.seller,sum(s.amount)
FROM invoiceRow s join InvoiceHead t
ON s.invoiceNr = t.invoiceNr
WHERE t.date between '01-01-2016' and '31-01-2016'
group by t.seller
You may try this once:
SELECT ih.Seller,
(
SELECT SUM(Amount) FROM invoicerow ir
INNER JOIN invoicehead ih1
ON (ir.InvoiceNr = ih1.InvoiceNr)
WHERE ih1.Seller = ih.Seller
) AS Amount
FROM invoicehead ih
GROUP BY ih.Seller
Related
I am trying to write a query to return supplier ID (sup_id), order date and the order ID of the first order (based on earliest time).
+--------+--------+------------+--------+-----------------+
|orderid | sup_id | items | sales | order_ts |
+--------+--------+------------+--------+-----------------+
|1111132 | 3 | 1 | 27,0 | 24/04/17 13:00 |
|1111137 | 3 | 2 | 69,0 | 02/02/17 16:30 |
|1111147 | 1 | 1 | 87,0 | 25/04/17 08:25 |
|1111153 | 1 | 3 | 82,0 | 05/11/17 10:30 |
|1111155 | 2 | 1 | 29,0 | 03/07/17 02:30 |
|1111160 | 2 | 2 | 44,0 | 30/01/17 20:45 |
|....... | ... | ... | ... | ... ... |
+--------+--------+------------+--------+-----------------+
Output I am looking for:
+--------+--------+------------+
| sup_id | date | order_id |
+--------+--------+------------+
|....... | ... | ... |
+--------+--------+------------+
I tried using a subquery in the join clause as below but didn't know how to join it without having selected order_id.
SELECT sup_id, date(order_ts), order_id
FROM sales s
JOIN
(
SELECT sup_id, date(order_ts) as date, min(time(order_date))
FROM sales
GROUP BY merchant_id, date
) m
on ...
Kindly assist.
You can use not exists:
select *
from sales
where not exists (
-- find sales for same supplier, earlier date, same day
select *
from sales as older
where older.sup_id = sales.sup_id
and older.order_ts < sales.order_ts
and older.order_ts >= cast(sales.order_ts as date)
)
The query below might not be the fastest in the world, but it should give you all information you need.
select order_id, sup_id, items, sales, order_ts
from sales s
where order_ts <= (
select min(order_ts)
from sales m
where m.sup_id = s.sup_id
)
select sup_id, min(order_ts), min(order_id) from sales
where order_ts = '2022-15-03'
group by sup_id
Assumed orderid is an identity / auto increment column
I'm trying to write a query which gives me the number of patient visits by age, gender and condition(Diabetes, Hypertension etc). Get the visit count for patients having diabetes and group by gender and patients who fall between the age range of 45-54. I used Inner Join to get only the rows which are present in both tables. I get the error:
age.Age is invalid in the select list because it is not contained in
either an aggregate function or the GROUP BY clause.
Do you think I should use partition by age.age?
TABLE_A
+------------+------------+------------+
| Member_Key | VisitCount | date |
+------------+------------+------------+
| 4000 | 1 | 2014-05-07 |
| 4000 | 1 | 2014-05-09 |
| 4001 | 2 | 2014-05-08 |
+------------+------------+------------+
TABLE_B
+------------+--------------+
| Member_Key | Condition |
+------------+--------------+
| 4000 | Diabetes |
| 4000 | Diabetes |
| 4001 | Hypertension |
+------------+--------------+
TABLE_C
+------------+---------------+------------+
| Member_Key | Member_Gender | Member_DOB |
+------------+---------------+------------+
| 4000 | M | 1970-05-21 |
| 4001 | F | 1968-02-19 |
+------------+---------------+------------+
Query
SELECT c.conditions,
age.gender,
CASE
WHEN age.age BETWEEN 45 AND 54
THEN SUM(act.visitcount)
END AS age_45_54_years
FROM table_a act
INNER JOIN
(
SELECT DISTINCT
member_key,
conditions
FROM table_b
) c ON c.member_key = act.member_key
INNER JOIN
(
SELECT DISTINCT
member_key,
member_gender,
DATEPART(year, '2017-10-16')-DATEPART(year, member_dob) AS Age
FROM [table_c]
) AS age ON age.member_key = c.member_key
GROUP BY c.conditions,
age.member_gender;
Expected Output
+--------------+--------+-------------+
| Condition | Gender | TotalVisits |
+--------------+--------+-------------+
| Diabetes | M | 2 |
| Hypertension | F | 2 |
+--------------+--------+-------------+
You can simplify your query filtering the age on the WHERE condition
And as Sean Lange said, use DATEDADD and GETDATE() to calculate the age more accurately.
SQL DEMO
SELECT [Condition],
[Member_Gender] as [Gender],
SUM([VisitCount]) as [VisitCount]
FROM TableA A
JOIN (SELECT DISTINCT [Member_Key], [Condition]
FROM TableB) B
ON A.[Member_Key] = B.[Member_Key]
JOIN TableC C
ON A.[Member_Key] = C.[Member_Key]
WHERE [Member_DOB] BETWEEN DATEADD(year, -50 , GETDATE())
AND DATEADD(year, -45 , GETDATE())
GROUP BY [Condition], [Member_Gender]
EDIT
Have to change the WHERE condition to solve the age precision and allow index use.
I have a database of transactions made by customers such that each transaction has a specific date. I need to count the number of transactions made by each customer in the last two months ONLY if there was a transaction made by the customer today.
I have been thinking that it requires me to use WHERE to set the complete range of two months and another HAVING statement to make sure the newest date (MAX of that customers transactions) is equal to today's date but I cannot seem to get it to work. Does this sound like the correct way to be going about this problem or is there a better way?
Thank you!
You don't provide any information about how your schema is, but I assume you have a Customer table and a Transaction table. Consider this example with 4 customers and 12 transactions.
Customers
| id | name |
|----|----------|
| 1 | Google |
| 2 | Facebook |
| 3 | Hooli |
| 4 | Yahoo! |
Transactions
| id | transaction_date | customer_id |
|----|------------------|-------------|
| 1 | 2017-04-15 | 1 |
| 2 | 2017-06-24 | 1 |
| 3 | 2017-07-09 | 1 |
| 4 | 2017-07-24 | 1 |
| 5 | 2017-07-23 | 2 |
| 6 | 2017-07-22 | 2 |
| 7 | 2017-07-21 | 2 |
| 8 | 2017-07-24 | 2 |
| 9 | 2017-07-24 | 3 |
| 10 | 2017-07-23 | 4 |
| 11 | 2017-07-22 | 4 |
| 12 | 2017-07-21 | 4 |
To count the number of transactions the last two months by each customer a simple group by will do the job:
select name, count(*) as number_of_transactions
from transactions t
inner join customers c on c.id = t.customer_id
where t.transaction_date > dateadd(month, -2, getdate())
group by c.name
This yields
| name | number_of_transactions |
|----------|------------------------|
| Facebook | 4 |
| Google | 3 |
| Hooli | 1 |
| Yahoo! | 3 |
To retrieve only customers that have a transaction with a transaction_date equal to today we can use an exists to check if such a row exist.
select name, count(*) as number_of_transactions
from transactions t
inner join customers c on c.id = t.customer_id
where t.transaction_date > dateadd(month, -2, getdate())
and exists(select *
from transactions
where customer_id = t.customer_id
and transaction_date = convert(date, getdate()))
group by c.name
So, if a row in the transaction table that has a transaction_date equal to today and the customer_id is equal to the customer_id from the main query include it in the result. Running that query (given that 24th July is today) gives us this result:
| name | number_of_transactions |
|----------|------------------------|
| Facebook | 4 |
| Google | 3 |
| Hooli | 1 |
Check out this sql fiddle http://sqlfiddle.com/#!6/710c94/13
You can toss a subquery in your WHERE clause to find customers that have had sales today:
SELECT count(*) /*count of transactions*/
FROM transactions
WHERE
/*Transactions in the last two months*/
transaction_date > DATEADD(mm, -2, GETDATE())
/*For customers that have had a sale today*/
customer_number in (SELECT customer_number FROM transactions WHERE transaction_date = GETDATE());
Totally guessing at your table structure, table name, and field names, but this should get you close.
Alternatively, you can try to do a inner join:
SELECT t2.CustomerID,count(*) as TransactionsCount
FROM [Tansaction] t1 INNER JOIN [Tansaction] t2
ON t1.CustomerID= t2.CustomerID
WHERE CONVERT(date,t1.TransactionDateTime) = CONVERT(date,GETDATE())
AND t2.TransactionDateTime>= DATEADD(mm, -2, GETDATE())
GROUP BY t2.CustomerID
First, you would need to get the list of customers that had made a transaction today. I'm assuming you have a 'transactiontable' that contains transaction dates and customer details.
Do a select from this transactiontable using the following method:
Select count of distinct(transactiondate), Customer
from Transactiontable
where transactiondate > dateadd(months,-2, getdate())
and customer in (select customer from transactiontable
`where cast(transactiondate as date) = cast(getdate() as date))
table structure is as follows
+---------------+---------+---------+
| customer_name | date | balance |
+---------------+---------+---------+
| 123 | june 14 | 20 |
| 123 | june 15 | 30 |
| 1234 | june 14 | 30 |
| 12345 | june 16 | 50 |
+---------------+---------+---------+
i would like to join on the same table, keeping my original data set as 2014 and i want to analyse trends to see which customers balance doesnt change from 2014.
for example i would like to show the below
+-----------+-----------+-----------+
| custmomer | june14bal | june15bal |
+-----------+-----------+-----------+
| 1234 | 30 | null |
| 123 | 20 | 30 |
+-----------+-----------+-----------+
I have trids multiple left joins but cant seem to get it working. the most important thing is starting my sample with records from 2014 only.
current script
with TABLE_DATA as
(
select Customer ,DATE, Balance
from table
where dATE in ('30-JUN-2014','30-juN-2015')
)
SELECT
sum(inv1.balance) as year1bal,
suminv2.balance) as year2bal,
customer,
date
from table_datA inv1
left join TABLE_DATA inv2
on inv1.customer= inv2.customer and inv2.as_of_Date = '30-June-2015'
group by date, customer
you can add having clause after group by Like:
having sum(inv1.balance) != sum(inv2.balance)
or try the below query
with table2014 as
(
select Customer ,sum(Balance) Balance2014
from tableName
where dATE ='30-JUN-2014' group by Customer
)
,Table2015 as
( select Customer ,sum( Balance) Balance2015
from tableName
where dATE ='30-juN-2015' group by Customer
)
SELECT
inv1.customer,Balance2014, Balance2015
from table2014 inv1
left join Table2015 inv2
on inv1.customer= inv2.customer
--where Balance2014 !=Balance2015
I am trying to pull some data with transaction counts, by branch, by week, which will later be used to feed some dynamic .Net charts.
I have a calendar table, I have a branch table and I have a transaction table.
Here is my DB info (only relevant columns included):
Branch Table:
ID (int), Branch (varchar)
Calendar Table:
Date (datetime), WeekOfYear(int)
Transaction Table:
Date (datetime), Branch (int), TransactionCount(int)
So, I want to do something like the following:
Select b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
LEFT OUTER JOIN TransactionTable t
on t.Branch = b.ID
JOIN Calendar c
on t.Date = c.Date
WHERE YEAR(c.Date) = #Year // (SP accepts this parameter)
GROUP BY b.Branch, c.WeekOfYear
Now, this works EXCEPT when a branch doesn't have any transactions for a week, in which case NO RECORD is returned for that branch on that week. What I WANT is to get that branch, that week and "0" for the sum. I tried isnull(sum(TransactionCount), 0) - but that didn't work, either. So I will get the following (making up sums for illustration purposes):
+--------+------------+-----+
| Branch | WeekOfYear | Sum |
+--------+------------+-----+
| 1 | 1 | 25 |
| 2 | 1 | 37 |
| 3 | 1 | 19 |
| 4 | 1 | 0 | //THIS RECORD DOES NOT GET RETURNED, BUT I NEED IT!
| 1 | 2 | 64 |
| 2 | 2 | 34 |
| 3 | 2 | 53 |
| 4 | 2 | 11 |
+--------+------------+-----+
So, why doesn't the left-outer join work? Isn't that supposed to
Any help will be greatly appreciated. Thank you!
EDIT: SAMPLE TABLE DATA:
Branch Table:
+----+---------------+
| ID | Branch |
+----+---------------+
| 1 | First Branch |
| 2 | Second Branch |
| 3 | Third Branch |
| 4 | Fourth Branch |
+----+---------------+
Calendar Table:
+------------+------------+
| Date | WeekOfYear |
+------------+------------+
| 01/01/2015 | 1 |
| 01/02/2015 | 1 |
+------------+------------+
Transaction Table
+------------+--------+--------------+
| Date | Branch | Transactions |
+------------+--------+--------------+
| 01/01/2015 | 1 | 12 |
| 01/01/2015 | 1 | 9 |
| 01/01/2015 | 2 | 4 |
| 01/01/2015 | 2 | 2 |
| 01/01/2015 | 2 | 23 |
| 01/01/2015 | 3 | 42 |
| 01/01/2015 | 3 | 19 |
| 01/01/2015 | 3 | 7 |
+------------+--------+--------------+
If you want to return a query that contains each Branch and each week, then you'll need to first create a full list of that, then use a LEFT JOIN to the transactions to get the count. The code will be similar to:
select bc.Branch,
bc.WeekOfYear,
TotalTransaction = coalesce(sum(t.TransactionCount), 0)
from
(
select b.id, b.branch, c.WeekOfYear, c.date
from branch b
cross join Calendar c
-- if you want to limit the number of rows returned use a WHERE to limit the weeks
-- so far in the year or using the date column
WHERE c.date <= getdate()
and YEAR(c.Date) = #Year // (SP accepts this parameter)
) bc
left join TransactionTable t
on t.Date = bc.Date
and bc.id = t.branch
GROUP BY bc.Branch, bc.WeekOfYear
See Demo
This code will create in your subquery a full list of each branch with each date. Once you have this list, then you can JOIN to the transactions to get your total transaction count and you'd return each date as you want.
Bring in the Calendar before you bring in the transactions:
SELECT b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
INNER JOIN CalendarTable c ON YEAR(c.Date) = #Year
LEFT JOIN TransactionTable t ON t.Branch = b.ID AND t.Date = c.Date
GROUP BY b.Branch, c.WeekOfYear
ORDER BY c.WeekOfYear, b.Branch