How to search records while ignoring the special characters in postgres - postgresql

I have a table in Postgres that has records like
ID
Address
1
862 N Longbranch Road Voorhees, NJ 08043
2
7300 Overlook, Ave Moncks Corner, SC 29461
3
76 SW Green Lake, Street Sterling, VA 20164
4
597 Wintergreen St Erlanger, KY 41018
So for searching a specific address my query is simple
select * from profile where address ilike '7300 Overlook, Ave Moncks Corner, SC%'
This is returning record 2
What I want is
select * from profile where address ilike '7300 Overlook Ave Moncks Corner SC%'
(Please note that commas are missing in second query)
Even if the string inside ilike doesn't contain comma , result 2 should be returned.

Related

SQL joins on phone_number where duration is less than 10min and returning only name column

I have 2 tables; phones and calls. and I am trying to write a SQL query that finds all clients who talked for at least 10 minutes in total. So the 'phone_number' in phones would match with the 'caller' and 'callee' column in calls and we can sum the durations to find which names have at least 10 minute calls.
phones
name phone_number
..................
Jack 1234
Lena 3333
Mark 9999
Anna 7582
calls
id caller callee duration
.............................
25 1234 7582 8
7 9999 7582 1
18 9999 3333 4
2 7582 3333 3
3 3333 1234 1
21 3333 1234 1
The query should return only the name column alphabetically.
name
.....
Anna
Jack
I know I have to use some type of join and aggregate function here but not sure how to start.
Anyone have any ideas?
Thanks!!
Join both tables on the caller column and group by name. Do the same for the callee column and UNION both results together. Then group by name and filter by SUM(duration).
SELECT name
FROM phones JOIN calls ON phones.phone_number = calls.caller
UNION
SELECT name
FROM phones JOIN calls ON phones.phone_number = calls.callee
GROUP BY name
HAVING SUM(duration) > 10;
Hi you can do it by using CTE (result here)
with call_duration as (
select caller as phone_number, sum(duration) as duration from calls group by caller
union all
select callee as phone_number, sum(duration) as duration from calls group by callee
)
SELECT name
FROM phones p join call_duration cd on cd.phone_number = p.phone_number
GROUP BY name
HAVING SUM(duration) >= 10
ORDER BY name

How do I find record above and below based on rank

I have a table called scoreboard and I want to fetch two player above and below based on rank for the arbitrary player.
For example, The given table contains the name and rating.
name
rating
Captain
2100
Ninja
1300
Mango
1760
Steve
1100
Benny
899
Zeus
800
Zeprus
1200
For a given player Zephrus, I need to show below records. Two above him and two below.
rank
name
rating
2
Mango
1760
3
Ninja
1300
4
Zeprus
1200
5
Steve
1100
6
Benny
899
How can I achieve this? I got to know how to find rank using the rank window function in PostgreSQL but not sure how do I achieve two above and two below for a given player effectively.
You can use the rank window function and select the rows with rank within 2 places from the name you're looking for:
with u as
(select *, rank() over(order by rating desc) as r from scoreboard),
v as
(select r from u where name ='Zeprus')
(select r, name, rating from u where abs(r - (select r from v)) <= 2 order by r)
Fiddle

split_part function from nth split till end of string

After the second space, I need to fetch the values till the particular position in the string.
Source:
"8 115 MACKIE STREET VICTORIA PARK WA 6100 AU"
"6A CAMBOON ROAD MORLEY WA 6062 AU"
output:
"MACKIE STREET VICTORIA PARK"
"CAMBOON ROAD MORLEY"
I'm trying to split the street name and suburb from the unit #,street# present in the beginning and the state, postcode, country present in the end.
t=# with s(v) as (values('6A CAMBOON ROAD MORLEY WA 6062 AU'),('8 115 MACKIE STREET VICTORIA PARK WA 6100 A'))
, split as (select *,count(1) over (partition by v) from s, regexp_matches(v,'( [A-Z]+)','g') with ordinality t(m,o))
select distinct v,string_agg(m[1],'') over (partition by v) from split where o <= count-(3-1);
v | string_agg
---------------------------------------------+------------------------------
8 115 MACKIE STREET VICTORIA PARK WA 6100 A | MACKIE STREET VICTORIA PARK
6A CAMBOON ROAD MORLEY WA 6062 AU | CAMBOON ROAD MORLEY
(2 rows)
I excluded index (or any not fitting mask [A-Z]+) thus cutting not three positions from the end, but two (3-1) where 1 is ahead known index.
Also I start not from the second space as it would be against your desired result...

Postgresql: two columns the same but third column different, display rows

I have 4 columns id, firstname, last name, reference. Most times the reference is the same but I need to display each row that has the same names, but a different reference in postgresql and order them by the id number. ONLY for those rows which someone has more than one reference. I've tried a bunch of things but just made a mess. Please assist.
For example:-
20 / John / Smith / 675
21 / John / Smith / 675
22 / John / Smith / 676
22 / Joe / Bloggs/ 651
24 / Joe / Bloggs/ 651
25 / John / Smith / 674
Should return all the John Smith rows, because one or more of his references is dissimilar
20 / John / Smith / 675
21 / John / Smith / 675
22 / John / Smith / 676
25 / John / Smith / 674
I can use this to get a count, but I want to display the full rows
select firstname, lastname, count (distinct id)
from transfer
group by firstname, lastname
having count(distinct id) >= 2
You don't need to count, you only have to check if (at least) one record with a different value for reference for the same person exists:
SELECT *
FROM transfer t
WHERE EXISTS (
SELECT * FROM transfer x
WHERE x.firstname = t.firstname -- same name
AND x.lastname = t.lastname
AND x. reference <> t.reference -- different reference
);
This is a possible answer:
select id, firstname, lastname, reference
from transfer t1
where 1 < (select count(distinct reference)
from transfer t2
where t1.firstname = t2.firstname and t1.lastname = t2.lastname)

Query to match multiple column values with multiple rows

I have the following table in my postgresql 9.1
Table contact:
contact_id phone mobile
1 123 456
2 111 222
3 333 123
4 222 444
Table role:
contact_fk exchange
7 1
8 2
1 4
5 5
2 4
4 5
I need the result like:
contact_id phone mobile exchange
1 123 456 4
3 333 123 4
2 111 222 4
I want all the contact data whose mobile field data is in any other contacts phone field and the user must be in exchange 4, which is available in contact_role table
FYI: the contact table contains around 50k rows so joining the contact table to itself taking a lot time, so we must apply the contact_role condition together.
Joining 50k table with 2 columns (where contact_fk is probably primary) shouldn't take long time.
SELECT t1.contact_id, t1.phone, t1.mobile, t2.exchange
FROM contact as t1
JOIN role as t2 ON t1.contact_id = t2.contact_fk
WHERE t2.exchange = 4
Or if you have index on exchange column, this probably will be faster:
SELECT t1.exchange, t2.contact_id, t2.phone, t2.mobile
FROM role as t1
JOIN contact as t2 ON t1.contact_fk = t2.contact_id
WHERE t1.exchange = 4
Here is the answer
select t1.contact_id,
t1.phone,
t1.mobile,
t2.phone,
t2.exchange
from contact t1
inner join (select contact_id,
mobile,
phone,
exchange
from contact, contact_role
where contact.contact_id = contact_fk
and exchange = 4
) t2
on t1.mobile = t2.phone
and t1.mobile != '';