Filtering out distinct donation records from a customer already in result set - ssms-2012

I need to find the top 50 largest donations from distinct customers. I can get the top 50 donation records, but several of those donation records are from the same customer. Is there a way to filter out donation records from a customer who already appears in the result set? Below is what I have to identify the top 50 donations:
SELECT TOP 50 gift_key
, customerName
, giftAmount
, giftDate
FROM gift (nolock)
JOIN customer (nolock) on gift_customer_key = customer_key
ORDER BY giftAmount desc

Related

How to group by twice or restrict a group by?

I have a location. A location has invoices. Invoices have fees. I want to get all the fees for a given month for a given location.
Here's what I can do:
SELECT
STR_TO_DATE(CONCAT_WS('-', YEAR(invoices.invoiceDate) , MONTH(invoices.invoiceDate), '01'), '%Y-%m-%d') as invoiceMonth,
AVG(fees.amount) as averageMonthlyInvoice,
SUM(fees.amount) as totalMonthlyInvoice
from invoices as invoices
inner join fees as fees
on fees.invoiceId = invoices.id
where invoices.locationId = 1
group by invoiceMonth
This second one would give me the average and total invoice information for an location. I want to be able to do this for all locations at once.
Here's what I want to do:
SELECT
invoices.locationId as locationId,
STR_TO_DATE(CONCAT_WS('-', YEAR(invoices.invoiceDate) , MONTH(invoices.invoiceDate), '01'), '%Y-%m-%d') as invoiceMonth,
AVG(fees.amount) as averageMonthlyInvoice,
SUM(fees.amount) as totalMonthlyInvoice
from invoices as invoices
inner join fees as fees
on fees.invoiceId = invoices.id
group by invoiceMonth, locationId
However, this last one would just average and total all invoices, not giving me the information for each specific location.
Perhaps using ORDER BY (conditions) might also help you get the data return you desire?

MySQL Complex Queries

Hey I've been killing myself trying to figure out how to do these queries. Can someone help me out.
These are the tables I have currently.
BOOKING
HOTEL_NO
GUEST_NO
DATE_FROM
DATE_TO
ROOM_NO
GUEST
GUEST_NO
GUEST_NAME
CITY
ADDRESS
ZIP_CODE
HOTEL
HOTEL_NO
HOTEL_NAME
CITY
ADDRESS
ZIP_CODE
STAR
ROOM
ROOM_NO
HOTEL_NO
ROOM_TYPE
PRICE
And these are the queries I need to do.
-List the guests that have all their bookings (past and present) in the same hotel.
-Create a view VIP-Guest that lists guests who have reservations for only 4 star hotels or
4 star hotels
-Among the VIPs find the guest with the largest total stay (in term of number of days).
Express this as a query with the view and without the view
Can someone help me out?
this should get you started. to post on stackoverflow, you need to come with specific questions or errors or problems. like for the query you posted in the comments up top.... that could be a question in itself: "I have these tables, this one specific goal (question/result set), and I tried this query... it gives me this result or it gives me this error."
BOOKING: HOTEL_NO, GUEST_NO, DATE_FROM, DATE_TO, ROOM_NO
GUEST: GUEST_NO, GUEST_NAME, CITY, ADDRESS, ZIP_CODE
HOTEL: HOTEL_NO, HOTEL_NAME, CITY, ADDRESS, ZIP_CODE, STAR
ROOM: ROOM_NO, HOTEL_NO, ROOM_TYPE, PRICE
all guests and bookings...
-- all guests: select * from guest;
-- all bookings: select * from booking;
select *
from guest
join booking on guest.guest_no = booking.guest_no;
-- which is the same as...
select *
from guest, booking
where guest.guest_no = booking.guest_no;
-- and... your comments query was missing a group by clause
select guest_no, guest_name, count(*) as booking_count
from guest
join booking on guest.guest_no = booking.guest_no
group by guest_no, guest_name;
select guest_no, guest_name, count(distinct hotel_no) as hotel_count
from guest
join booking on guest.guest_no = booking.guest_no
group by guest_no, guest_name
having count(distinct hotel_no) = 1;
and I count(distinct hotel_no) because... they might have 3 bookings at Hotel A and 1 at Hotel B. The basic join would give me 4 rows for that person. I don't care how many bookings. I care how many hotels. So I want to count the distinct occurrences of hotel_no per person (there's that group by) instead of every row.
guests by their stars...
-- so we have to get guest and hotel joined. bc hotel has stars.
-- booking has hotel_no. so... we can use that last query and
-- join in HOTEL to get the star information. in the WHERE you
-- will want to put your filter for the number of stars that you
-- are looking for =4 or >=4 or something like that.
-- you might want to check out DISTINCT to get just a list of names
-- instead of a row for each booking.
number of days they stayed...
-- use the second query.
-- datediff(date_to, date_from) as days_stay gives you the length of stay
-- i don't know what the view is.
-- to get the top length could go two ways... either ORDER BY and LIMIT if there is
-- only one person with the top length (let's say 10 days). if there are many people
-- who have stayed 10 days, you'll need to do a MAX on the days_stay and either join
-- that in or use it in the WHERE as a nested select.
this assumes there is a single highest length of stay. only one person stayed 10 days.
SELECT guest_no, guest_name, datediff(date_to, date_from) days_stayed
FROM vip_guest
join booking on vip_guest.guest_no = booking.guest_no
order by datediff(date_to, date_from) desc
limit 1,1
this should work for many... (i'm not testing these... just kind of looking at it)
SELECT distinct guest_no, guest_name, datediff(date_to, date_from) max_stay
FROM vip_guest
join booking on vip_guest.guest_no = booking.guest_no
where datediff(date_to, date_from) = (
select max(datediff(date_to, date_from)) as days_stayed
from booking )
the nested query gets the maximum stay length of everyone. vip_guest and bookings joined together give us guest and date imfo. we will get all bookings for every vip_guest. so we want to filter it down to where stay lengths == the max stay length. in case a person had multiple 10 day stays (my arbitrary max stay length)... use distinct.
now... thats a good point about the nested query. i don't know what is in your view. it is possible none of the max vip guests had a stay as long as the max stay length. in that case, this query would return nothing.

Find customers with more than 1 order grouped by day

I want to know how many customers placed more than 1 order, grouped by day.
But I want to exclude orders that have been cancelled.
I have a customer table with customers
I have a customer_order table with orders (when an order is cancelled
it stays in the customer_order table)
I have an order_item table (where original orders are, and also
cancelled orders, cancelled orders get a new credit order, and the
original order id appears in the id_credit_order row of the credit
order)
I want something like this:
date | no of customers with 1 order | no of customers with 2 orders | no of customers with 3 order | etc.
But I want no count if the original order has been cancelled!
I have now this query, but its definitely not enough, does someone know how to get my result? thanks!
SELECT DATE(co.date_order), COUNT(co.id_customer)
FROM customer_order co
GROUP BY DATE(co.date_order)
ORDER BY DATE(co.date_order) DESC;
The question is slightly misleading, as you first ask for the number of customers with more than one order, then you ask for the number of customer with each of 1, 2, 3... orders.
Here's something that will give you the numbers, but unpivoted. You'll need to put the right column name in for o.id
Select -- outer query takes each order count and counts how many customers have that many
co.date_order,
co.customer_order_count,
count(*) as customer_count
From (
Select -- inner query counts how many valid orders each customer has
o.date_order,
o.id_customer,
count(*) as customer_order_count
From
customer_order o
Where
o.id_credit_order is null and -- rule out credit orders
not exists ( -- rule out orders with related credit orders
select
'x'
from
customer_order c
where
c.id_credit_order = o.id -- column name isn't mentioned in the question
)
Group By
o.date_order,
o.id_customer
) co
Group By
co.date_order,
co.customer_order_count
Order By
co.date_order desc,
co.customer_order_count
Try using a HAVING clause.
SELECT DATE(co.date_order), COUNT(co.id_customer)
FROM customer_order co
WHERE co.Cancelled = 0
GROUP BY DATE(co.date_order)
HAVING COUNT(co.id_customer) >= 1
ORDER BY DATE(co.date_order) DESC;
Give this a try. Change the WHERE to reflect how you cancel orders.
SELECT DATE(co.date_order), COUNT(co.id_customer)
FROM customer_order co
WHERE co.cancelled = 0
GROUP BY DATE(co.date_order)
HAVING COUNT(co.id_customer) > 0
ORDER BY DATE(co.date_order) DESC;

A cleaner way to do this SQL query

So have a list of customers, that have a list of customers.
I have 2 tables, customers and invoices.
Customer_id can be the same for my customers e.g
Client A
Customer #1
Client B
Customer #1
So invoice table can have customer_id of 1, for different customers.
The below query works, but seems a little messy. Any ideas to clean it up?
SELECT name,
sum(sub_total) total
FROM customers, invoices
WHERE customer_id = 1438 and
invoices.customer_id = 1438 and
customers.customer_id = invoices.customer_id
GROUP BY name
Order By total DESC;
If A = B and A = 1438 then B = 1438 you don't need to check it...
(Trust me on this one, I got 60+ in math in highschool)
SELECT name, sum(sub_total) total
FROM customers, invoices
WHERE invoices.customer_id = 1438
AND customers.customer_id = invoices.customer_id
GROUP BY name
ORDER BY total DESC;
Or with explicitly saying which type of JOIN you want:
SELECT name, sum(sub_total) total
FROM customers INNER JOIN invoices
ON customers.customer_id = invoices.customer_id
WHERE invoices.customer_id = 1438
GROUP BY name
ORDER BY total DESC;
you dont need the extra check...
SELECT name, sum(sub_total) total
FROM customers, invoices
WHERE
customer_id = 1438 and
customers.customer_id = invoices.customer_id
GROUP BY name order by total DESC;
I would strongly NOT do a group by on name... Say you have two customers named "Bill Smith", but one is customer ID 10, and the other is customer ID 785... You just combined them into a single person. You SHOULD be grouping by ID, not the name...
Now, that said, you are querying for only a single customer ID anyhow and will only ever return a single record. If what you are really trying to accomplish is getting ALL customers and the tot of their respective invoices, remove the where clause of the single customer. You can keep the group by ID, but show the actual customer's name. If you have multiple customers with the same total, you can sub-sort by their name, but the grouping is STILL based on just the customer's ID.
SELECT
c.name,
sum(i.sub_total) total
FROM
customers
JOIN invoices
on c.Customer_ID = i.Customer_ID
GROUP BY
c.customer_ID
Order By
total DESC,
c.Name

Access database returns double SUM for field Income

I have the following query in access 2003 mdb.
SELECT Company.Name, Company.Address, Place.Name_of_Place, Sum(Income.Value) AS Income, Sum(Invoice.Value) AS Invoice
FROM ((Company LEFT JOIN Invoice ON Company.CompanyID = Invoice.CompanyID) LEFT JOIN Income ON Company.CompanyID = Income.CompanyID) INNER JOIN Place ON
Place.Postal = Company.Postal
GROUP BY Company.Name, Company.Address, Place.Name_of_Place, Company.CompanyID
HAVING ((iif(IsNull(Sum(Invoice.Value)), 0, Sum(Invoice.Value)) - iif(IsNull(Sum(Income.Value)), 0, Sum(Income.Value))) > 0)
ORDER BY Company.Name;
Income field value is 500, but query returns 1000.
There must be something with those Left joins that this Income table is twice searched.
How to solve this?
I'm thinking to in my program do simple division by 2 for this column, but I'd rather like to solve this on database level.
Regards,
Vajda
When you join the Company with the Invoice, the result will have as many rows as the rows in Invoice. So if a company has 2 invoices, you will have 2 rows.
Then, when you join that with the Income (which I am not sure how many rows per company it has) the result will be 2 rows for each row of Income.
You will have to resort to sub-queries, like this:
SELECT
Company.Name,
Company.Address,
Place.Name_of_Place,
(SELECT SUM(Income.Value) FROM Income WHERE Income.CompanyID=Company.CompanyID) AS Income,
(SELECT SUM(Invoice.Value) FROM Invoice WHERE Invoice.CompanyID=Company.CompanyID) AS Invoice
FROM
Company INNER JOIN Place ON Place.Postal = Company.Postal
WHERE
Invoice - Income > 0
ORDER BY
Company.Name;