SQL Server: how to limit results based on query - sql

I have a customer table, and a customer address table but I want to limit it by just one address. so even though a customer has two postal addresses I want to show only one for each customer. Forgive me if this is a silly question, I am new to programming
custid forename surname
---------------------------
1 Sam Supra
2 Kelly Kenwood
addid custid address addresstype
-------------------------------------------
1 1 Main street POSTAL
2 1 2nd Main street POSTAL
3 1 0712456254 Mobile
4 1 0526545686 LANDLINE
5 2 Second Street POSTAL
6 2 04756325654 Mobile
7 2 058654236545 LANDLINE
Query:
SELECT a.*
FROM dbo.customers a
LEFT OUTER JOIN dbo.addresses b ON a.custid = b.custid
WHERE b.addresstype = 'POSTAL'

You can use ROW_NUMBER():
SELECT c.*, a.*
FROM dbo.customers c LEFT JOIN
(SELECT a.*,
ROW_NUMBER() OVER (PARTITION BY a.custid ORDER BY a.addid DESC) as seqnum
FROM dbo.addresses a
WHERE a.addresstype = 'POSTAL'
) a
ON a.custid = c.custid AND seqnum = 1;
Notes:
Don't use arbitrary table aliases. Use abbreviations for the table names.
Presumably, you want to select the addresses, so I changed the SELECT clause.
This returns all customers, even those with no address. I am guessing that is your intention, although your query would return only customers with a postal address.

I assume you are interested in the last address entered:
SELECT
*
FROM
dbo.customers a
LEFT JOIN
dbo.addresses b on b.id =
(
SELECT
x.id
FROM
dbo.addresses x
WHERE
x.custid = a.custid
AND
x.addresstype = 'POSTAL'
ORDER BY
x.id DESC
)

SELECT c.*,
a.*
FROM dbo.customers c
LEFT JOIN (
SELECT a.*,
ROW_NUMBER() OVER (
PARTITION BY a.custid
ORDER BY a.addid DESC
) as seqnum
FROM dbo.addresses a
WHERE a.addresstype = 'POSTAL'
) a
ON a.custid = c.custid AND seqnum = 1;

Related

Oracle SQL: show max when record in table exists

If record exists in the table i need to bring the data from the highest address record linked to the person.
Example:
John Doe have no address at all. Report need to still bring John Doe name but nothing as an address.
John Doe have 3 addresses with address number increasing. Report need to bring John Doe name and only the address with the highest address number.
Code I tried:
Select *
from person p left join address a on p.id = a.person and a.addressnumber = (select max(a2.addressnumber) from address a2 where a2.a_peron = p.id)
Oracle returns error: ORA-01799: a column may not be outer-joined to a
subquery
01799. 00000 - "a column may not be outer-joined to a subquery"
I also tried
Select *
from person p left join address a1 on p.id = a1.person
inner join (select a.person, max(a.addressnumber) MaxAdd, a.postcode, a.country from address a group by a.person, a.postcode, a.country) main on main.person = p.id and main.MaxAdd = a1.addressnumber
This doesnt work neither due to the grouping.
I can probably get this done by using subqueries in the select itself together with the case statement but i would like to avoid that because I will be pulling a lot of data from the address so this would mean case statement with subquery for every single column.
Oracle 11g - 11.2
Any idea? :D
You can use ROW_NUMBER to rank your rows and only keep the last one:
select *
from person p
left join
(
select
ad.*,
row_number() over (partition by person order by addressnumber desc) as rn
from address ad
) a on a.person = p.id and a.rn = 1;
Please try this:
select * from
person p left join
(select a.person, max(a.addressnumber) MaxAdd, a.postcode, a.country from address a
group by a.person, a.postcode, a.country) A
on p.id=A.person
Use row_number():
Select *
from person p left join
(select a.*,
row_number() over (partition by a.person order by a.addressnumber desc) as seqnum
from address a
) a
on p.id = a.person and seqnum = 1;

Display the city name which has most number of branches

I have tried to get city name which has most number of branches .
select C.City_name ,count(B.B_Name)
from tblcity C
inner join
tblBranch B
on c.city_id=B.City_id
group by C.City_name
order by count(B.B_Name) desc
Above code will give me the count of branches for particular city .
Please help me solve to get city name which has most number of branches
you can add TOP 1 to your query
select TOP 1 C.City_name ,count(B.B_Name)
from tblcity C
inner join
tblBranch B
on c.city_id=B.City_id
group by C.City_name
order by count(B.B_Name) desc
Use DENSE_RANK():
SELECT
City_Name, cnt
FROM
(
SELECT
c.City_name,
COUNT(b.B_Name) cnt,
DENSE_RANK() OVER (ORDER BY COUNT(b.B_Name) DESC) dr
FROM tblcity c
INNER JOIN tblBranch b
ON b.city_id = c.City_id
GROUP BY c.City_name
) t
WHERE dr = 1;
Using TOP 1 WITH TIES would be another option here, but that is specific to SQL Server.

SQL query to find a record which has all matching records in another table

I have below 3 tables and I want to write a SQL query which will list the store present in all city: (here the result should be "Walmart")
Stores:
ID Name
1 Walmart
2 Target
3 Sears
Stores_City
ID Store_id City ID
1 1 10
2 1 20
3 2 10
4 1 30
City
ID Name
10 NewYork
20 Boston
30 Eagan
I am unable to find a query that works. Any help is appreciated!
select s.Name
from Stores s
inner join
(
select store_id, count(distinct city_id)
from stores_city
group by store_id
having count(distinct city_id) = (select count(*) from City)
) x
on x.store_id = s.id;
You can do it by grouping on store_id and checking for the count from stores table.
A straight join would work
Select distinct s.name from stores s inner join store _city SC on s.id=sc.id
Inner join city c on
Sc.city_id = c.id
Here is another way that will work:
select s.*
from stores s
where not exists (
select c.id
from city c
except
select sc.city_id
from stores_city sc
where sc.store_id = s.id
)
Try this:
SELECT
s.Name
FROM Stores s
WHERE NOT EXISTS (SELECT TOP 1
1
FROM City c
LEFT JOIN Stores_City sc
ON c.ID = sc.CityID
AND sc.Store_id = s.ID
WHERE sc.ID IS NULL)

SQL - Select only last order for every clients who had ordered before

There are 2 tables, and I want to select only last order for each client that has ordered before...
(cid,cname) Clients table
1 , David
2 , Tom
3 , Alex
(oid,cid,title,ordertime) Orders table
1,1,"Tshirt",2013-10-1
2,3,"Ball",2013-10-1
3,3,"Food",2013-11-20
*Acording to tables Tom never ordered before. So he will not be listed. Alex ordered 2 times before and I want only show last order.
Output must be like this :*
1,1,"Tshirt",2013-10-1, David
3,3,"Food",2013-11-20, Alex
I tried something like this code but Alex was listed 2 times. I dont understand how I can figure out.
select *
from Clients t2
left join Orders t1
on t1.cid=t2.cid
where t1.ordertime<getutcdate()
order by t1.ordertime desc**
Probably I must use Distinct or Group by but I dont understand how.
Select
x.oid,
x.cid,
x.title,
x.ordertime,
x.cname
From (
Select
o.oid,
o.cid,
o.title,
o.ordertime,
c.cname,
row_number() over (partition by o.cid order by o.ordertime desc) rn
From
Clients c
inner join
Orders o
on c.cid = o.cid
) x
Where
x.rn = 1
SELECT o.*, c.name
FROM orders o INNER JOIN clients c on o.cid = c.cid
INNER JOIN (SELECT MAX(oid) as latestOrderid, cid FROM orders GROUP BY cid) as latest
on latest.latestorderid= orders.oid
Try this:
select o.*, c.cname
from clients c
join orders o on
c.cid = o.cid
and not exists (select *
from orders o2
where o2.cid = o.cid
and o2.ordertime > o.ordertime)

SQL First row only following aggregation Rules

I need to select only the most significant value from a table. Using Postgre SQL (last version) Follows the data sample:
Table Company
Id, Name, ExternalId, StartAt
1 Comp1 54123 21/05/2000
2 Comp2 23123 21/05/2000
Table Address
Id, Company, Address_Type, City
1 1 7 A
2 2 2 B
3 2 62 C
Table Adress_Type
Id, Name, importance_order
62 Adt1 1
7 Adt2 2
2 Adt3 2
What i need to do is to get the company and its major Address, based on the "importance_order". There is already a function that returns this result:
Create function~~~~
Select * from Company c
join Address a on c.address_id = a.id
Join AddressType at on a.adresstype_id = at.id
ORDER by at.importance_order
Limit 1
My problem now is that this function is called one time for every row in the query, and it take so much time (about 20 min.). Should it be possible to do this similar aproach by joinning tables? I need this join to get the First "most important"address, and then get the City name, but need to do this in a "faster" way. I need to reduce subquery`s number to its minimal.
Select * from table t
inner join Company c on t.company_id = c.id
left join address a on (c.company_id = c.id)
left join addresstype at on (a.adresstype_id = at.id)
where at.id = (
select max(id) from addresstype
where adresstype in (
select adresstype from adress where company_id = c.id
)
)
If it is not clear tell me that i get more into details.
Thanks.
For this you need PostgreSQL 8.4+ I suppose
SELECT T.*
FROM TABLE AS T
INNER JOIN
(
SELECT * FROM
(
SELECT C1.*, ROW_NUMBER() OVER(partition by C1.ID ORDER BY T.IMPORTANCE_ORDER) AS RN
FROM COMPANY AS C1
INNER JOIN ADDRESS AS A
ON C1.ID = A.COMPANY
INNER JOIN ADDRESS_TYPE AS T
ON T.ID = A.ADDRESS_TYPE_ID
) A
WHERE RN = 1
) AS B
ON B.ID= T.COMPANY_ID