Take one condition & show result from two different tables - sql

I have these 3 data tables (quick version):
Payments:
id | datepaid | amountpaid
---------------------------
112|03/5/2017 |9000
115|03/21/2017| 800
Individuals:
id|name|lastDatePaid
--------------------
112|bob|03/2/2017
114|kary|2/3/2016
Business:
id|name|lastDatePaid
--------------------
115| Bakery Love | 05/20/2017
My question is: how would I get the result of both business name and individual name when the condition is the for each payment that was made on or after March 2, 2017?
I was able to get show result in one condition, but I don't seem to understand to get both individual and business to show up?
Want result:
112|bob
115|Bakery Love
This is my version that one result show for example Individual:
SELECT DISTINCT p1.id, i1.name
FROM Payments p1, Individuals i1
WHERE p1.datePaid >= DATE '2017-03-01' AND p1.id = i1.id;
Which this code result only to:
112|bob
Also I've read a book that this code is also equivalent, but I don't think so?
SELECT DISTINCT p1.id, i1.name
FROM Individuals i1, Payments p1
WHERE i1.id IN (SELECT DISTINCT p1.id
FROM Payments p1
WHERE p1.datePaid >= DATE '2017-03-01');
When I rewrote it to try to get the same result, I ended up getting unwanted data for some reason. Apparently, it checks the dates (lastDatePaid) in the Individual and businesses table and print without having that AND condition that it should be the id from the payments.(this is the full version of the data).

One approach you could take is to put the 'name' tables on top of each other.
Select * from individuals
Union all
Select * from business
Then you make that a sub query and join it to the payment table...
Select p.id, n.name
From
Payments p
Join
(
Select * from individuals
Union all
Select * from business) as n
On n.id = p.id
It looks like you have figured how to get the date filter to work, so I won't bother adding that.

Er, I figure it out.
I didn't need to use the JOIN statement rather this
SELECT DISTINCT p1.ID, N.name
FROM Payments p1, (SELECT i1.name, i1.ID
FROM Individuals i1
UNION ALL
SELECT b1.name, b1.ID
FROM Businesses b1) AS N
WHERE p1.datePaid >= DATE '2017-03-01' AND p1.ID = N.ID;

Related

Combine max and columns in a single query

I have 2 tables:
customer -> int ID, string NAME
purchase -> date DATE, int VALUE, int C_ID
In the table customer I have:
1, A
2, B
In the table purchase:
01-01-2019, 10, 1
02-01-2019, 20, 2
03-01-2019, 30, 2
I'd like to do a single query that will return the latest purchase for each Customer. So I'd like to get:
1, 01-01-2019
2, 03-01-2019
I've tried different select without success:
select max(purchase.date), customer.id
from customer, purchase
where purchase.c_id = customer.id
But the result is only:
2, 03-01-2019
So I cannot get the max per each line...
Is it possible? Can you help me?
I would recommend filtering as opposed to aggregation:
select p.*
from purchases p
where p.date = (select max(p2.date) from purchases p2 where p2.c_id = p.c_id);
Basically, your query just needs a GROUP BY clause. Without it, all records are aggregated into a unique row, which contains the maximum date and a randomly picked customer id.
If you only need the customer id and date, there is no need to involve the customer table:
select c_id, max(date) from purchase group by c_id
If you need information that come from the customer table (like the customer name), then:
select max(p.date), c.id, c.name
from customer c
inner join purchase p on p.c_id = c.id
group by c.id, c.name
Note:
always use prefer explicit standard joins over old-school implicit joins
using table aliases make the query shorter and easier to read

How can I sum data from mulitple rows which have the same foreign key into one row?

I have two tables which have a 1 to n relation. One table contains general Information of a bill (named bill)
(< -1 to n ->)
and the other contains Items which are on the bill (named items). I want a query that Lists all Bills and sums up the prices from the items in a new row. But of course i want every Bill listed just once not for every item.
Usually i don't post anything. But i can't find an answer because i don't know how to search for this problem. Sorry when this is obvious.
What my tables look like:
bill:
bill_id - customer - date
items:
item_id - bill_id - amount - price
A simple join with aggregation should work here:
SELECT
b.bill_id,
COALESCE(SUM(i.price), 0) AS total_price
FROM bill b
LEFT JOIN items i
ON b.bill_id = i.bill_id
GROUP BY
b.bill_id;
If you want to include the other two columns from the bill table, then just add them to the SELECT and GROUP BY clauses.
You may try this.
; with cte as (
select b.bill_id, i.item_id ,isnull(i.price,0) as Price from
Bill as b inner join items as i on b.bill_id =i.bill_id
union all
select b.bill_id , null, sum(isnull(i.price,0)) from
Bill as b inner join items as i on b.bill_id =i.bill_id
group by b.bill_id
)
select * from cte order by bill_id, item_id desc

Oracle sql query that returns customers who are coming for the first time in property

I have 3 tables: customer, property and stays. Table customer contains all the data about customers (customer_id, name, surname, email...). Table property contains the list of all the properties (property_id, property_name...) and table stays contains all the earlier stays of customers (customer_id, property_id, stay_id, arrival_date, departure_date...).
Some customers stayed multiple times in more than one properties and some customers are coming for the first time.
Can someone please explain oracle sql query which returns only the customers who are stying in any of the properties for the first time.
Sorry guys for answering late..
This is what I got so far.
Tables:
Customer $A$
Stays $B$
Property $C$
Customer_Fragments $D$
SELECT a.RIID_,
sub.CUSTOMER_ID_,
sub.PROPERTY_ID,
b.ARRIVAL_DATE,
c.PROPERTY_SEGMENT,
ROW_NUMBER() OVER (
PARTITION BY sub.CUSTOMER_ID_,
sub.PROPERTY_ID
ORDER BY
sub.CUSTOMER_ID_ asc
) RN
FROM
(
SELECT
b.CUSTOMER_ID_,
b.PROPERTY_ID
FROM
$B$ b
GROUP BY
b.CUSTOMER_ID_,
b.PROPERTY_ID
HAVING
COUNT(*)= 1
) sub
INNER JOIN $A$ a ON sub.CUSTOMER_ID_ = a.CUSTOMER_ID_
INNER JOIN $B$ b ON sub.CUSTOMER_ID_ = b.CUSTOMER_ID_
INNER JOIN $C$ c ON sub.PROPERTY_ID = c.PROPERTY_ID
LEFT JOIN $D$ d ON a.RIID_ = d.RIID_
WHERE
b.ARRIVAL_DATE = TRUNC(SYSDATE + 7)
AND c.PROPERTY_DESTINATION = 'Destination1'
AND lower(c.NAME_) NOT LIKE ('unknown%')
AND a.NWL_PERMISSION_STATUS = 'I'
AND a.EMAIL_DOMAIN_ NOT IN ('abuse.com', 'guest.booking.com')
AND (d.BLACKLISTED != 'Y'
or d.BLACKLISTED is null
)
I want to select all customers who will come to Destination1, 7days from today to inform them about some activities. Customers can book several
properties in Destination1 and have the same arrival date (example: I can book a room in property1 for me and my wife and also book a room in property2 for my friends.. and we all come to destination1 on the same arrival date).
When this is the case I want to send just one info email to a customer and not two emails. The above SQL query returns two rows when this is the case and I want it to return just one row (one row = one email).
It is always required to post a code you have already tried to write so that we can than help you with eventual mistakes.
After that being said, I'll try to help you nevertheless, writing the full code.
Try this:
select cus.*
from customers cus
join stays st
on st.customer_id = cus.customer_id
where st.arrival_date >= YOUR_DATE --for example SYSDATE or TRUNC(SYSDATE)
and 1 = (select count(*)
from stays st2
where st2.customer_id = cus.customer_id)
You haven't specified it, but I GUESS that you are interested in getting the first-time-customers whose arrival date will be at or after some specified date. I've written that into my code in WHERE clause, where you should input such a date.
If you remove that part of the WHERE clause, you'll get all the customers that stayed just once (even if that one and only stay was 10 years ago, for example). What's more, if you remove that part of the code, you can than also remove the join on stays st table from the query too, as the only reason for that join was the need to have access to arrival date.
If you need explanations for some other parts of the code too, ask in the comments for this answer.
I hope I helped!
WITH first_stays (customer_id, property_id, first_time_arrival_date, stay_no) AS
(
SELECT s.customer_id
, s.property_id
, s.arrival_date AS first_time_arrival_date
, ROW_NUMBER() OVER (PARTITION BY s.customer_id, s.property_id ORDER BY s.arrival_date) stay_no
FROM stays s
)
SELECT c.surname AS customer_surname
, c.name AS customer_name
, p.property_name
, s.first_time_arrival_date
FROM customer c
INNER
JOIN first_stays s
ON s.customer_id = c.customer_id
AND s.stay_no = 1
INNER
JOIN property p
ON p.property_id = s.property_id
The first part WITH first_stays is a CTE (Common Table Expression, called subquery factoring in Oracle) that will number the stays for each pair (customer_id, property_id) ordered by the arrival date using a window function ROW_NUMBER(). Then just join those values to the customer and property tables to get their names or whatever, and apply stay_no = 1 (first stay) condition.
If I understand the question correctly, this is not a complicated query:
select c.*
from c join
(select s.customer_id
from stays s
group by s.customer_id
having count(*) = 1
) s
on s.customer_id = c.customer_id;

HQL query with 2 column Sub Join

I have a table price:
| id | price | product_id | date | other_columns... |
I have the following query to return the latest price row for each product_id:
select p1.*
from price p1
right join (
select
p2.product_id,
p2.id,
max(p2.date)
from price p2
GROUP BY p2.product_id
) p2 ON p2.id = p1.id;
When I run Explain plan, and from running against a large table this seems to be the most efficient way of achieving this (correct me if I'm wrong!).
I need to convert this to HQL to use with Spring Data JPA. So far I have the sub query:
(SELECT p2.id, MAX(p2.date) FROM Price p2 GROUP BY p2.product)
That seems to be the easy part. How do I now join this so I can get the full latest Price for each product?
I have tried other queries e.g.
select
p1.*
from price p1
where p1.date = (
select max(p2.date)
from price p2
where p1.product_id = p2.product_id
)
Which is much easier to convert to HQL but seems to be worse performance-wise.

Retrieve records from multiple Records returned by Sub-Query

I have this database Diagram :
the diagram is represent a database for Insurance Company.
the final_cost table represent the cost that the company should paid to repair a car
the table car has the field car_type which take one of the following values (1,2,3) where 1 refers to small cars, 2 refers to trucks , 3 refers to buses
I want to retrieve the name of kind (1 or 2 or 3 ) which has the maximum repaired cost during the 2013 year
I wrote The following Query :
select innerr.car_type from (
select car_type ,sum(fina_cost.cost) from car_acc inner join cars on cars.car_id = car_acc.car_id
inner join final_cost on FINAL_COST.CAR_ACC_ID = car_acc.CAR_ACC_ID
where (extract(year from final_cost.fittest_date)=2013)
group by(car_type)) innerr;
but I don't know how to get the car_type with maximum repaired Cost from the inner Sub-Query !
You can have access to anything and everything from a subquery if you use it right. The best way to build a complicated query is to start simply, seeing what data you have and usually the answer, or the next step, will be obvious.
So let's start by displaying all the accidents for 2013. We aren't interest in the individual cars, just the most expensive accidents by type. So...
select c.car_type, f.cost
from car_acc a
join cars c
on c.car_id = a.car_id
join final_cost f
on f.car_acc_id = a.car_acc_id
where f.fittest_date >= date '2013-01-01'
and f.fittest_date < date '2014-01-01';
I've changed the filtering criteria to a sargable form for efficiency. I don't usually worry about performance early in the design of a query, but when it's this obvious, why not?
Anyway, we now have a list of all 2013 accidents, by car type and the cost of each one. So now we only have to group by the type and take the Max of the cost of each group.
select c.car_type, Max( f.cost ) MaxCost
from car_acc a
join cars c
on c.car_id = a.car_id
join final_cost f
on f.car_acc_id = a.car_acc_id
where f.fittest_date >= date '2013-01-01'
and f.fittest_date < date '2014-01-01'
group by c.car_type;
Now we have a list of car types and the most expensive accidents for that type for 2013. With only three rows in the result set, it's easy to see which is the car type we're looking for. Now we just have to isolate that one row. The easiest step from here is to use this query in a CTE.
with MaxPerType( car_type, MaxCost )as(
select c.car_type, Max( f.cost ) MaxCost
from car_acc a
join cars c
on c.car_id = a.car_id
join final_cost f
on f.car_acc_id = a.car_acc_id
where f.fittest_date >= date '2013-01-01'
and f.fittest_date < date '2014-01-01'
group by c.car_type
)
select m.car_type, m.MaxCost
from MaxPerType m
where m.MaxCost =(
select Max( MaxCost )
from MaxPerType );
So the CTE gives us the largest cost per type and the subquery in the main query gives us the largest cost overall. So the result is the type(s) that match the largest cost overall.
You could try either orderby or better yet, use the Max Function http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions085.htm
Try this:
SELECT A.car_type
FROM (SELECT c.car_type, SUM(fc.cost) totalCost
FROM car_accident ca
INNER JOIN cars c ON c.car_id = ca.car_id
INNER JOIN final_cost fc ON fc.CAR_ACC_ID = ca.CAR_ACC_ID
WHERE EXTRACT(YEAR FROM fc.fittest_date) = 2013
GROUP BY c.car_type
ORDER BY totalCost DESC
) AS A
WHERE ROWNUM = 1;