Postgreql. How to select unique values and count it? - sql

I have column in postgresql
Names
Mike
Alex
Mike
Bill, Abigail
Abigail
Bill
Kurt, Adele, John
Mike
John
, is a delimiter when values two or more in the field.
How to to select it as result
Abigail 2
Adele 1
Alex 1
Bill 2
John 2
Kurt 1
Mike 3
I read about distinct and join but I can't make query.

You need to split the values and then count:
select u.name, count(*)
from t cross join lateral
unnest(string_to_array(names, ', ')) u(name)
group by u.name;
Here is a db<>fiddle.
Then you should fix your data model. Do not store multiple values in a string column. Postgres supports arrays which is one option. Another is a proper junction/association table.

Related

proc sql function to find mulitple LIKE matches?

I'm having trouble with a LIKE function in proc sql.
PROC SQL;
CREATE TABLE NAMES_IDS AS
SELECT DISTINCT
T1.*
,T2.NAMES
,T2.NAME_ID
FROM WORK.table1 T1
LEFT JOIN data.table2 T2 ON T2.NAMES like T1.NAMES1
;QUIT;
I have several names in t2, lets say for example theres John 1, John 2, John 3, John 4, etc and in t1.Names1 there is %John%
proc sql is just pulling in the first match, John 1 and its associated ID, and applying it to all the data in T1, instead of duplicated a match for all matching names (this is what I want to achieve).
So the end table would have something like
COLUMN A COLUMN B
John John 1
John John 2
John John 3
John John 4
But instead, what I get is:
COLUMN A COLUMN B
John John 1
John John 1
John John 1
John John 1
Hopefully this makes some sort of sense...
I think I figured it out, I added TRIM to my code and I guess there may have been some erroneous spaces somewhere because that seems to fix my issue. Thanks for your responses!

Finding distinct count of combination of columns values in sql

Currently I have a table this :
Roll no. Names
------------------
1 Sam
1 Sam
2 Sasha
2 Sasha
3 Joe
4 Jack
5 Jack
5 Julie
I want to write a query in which I get count of the combination in another column
Required output
Combination distinct count
-----------------------------
2-Sasha 1
5-Jack 1
5-Julie 1
Basically, you could group by these columns and use a count function:
SELECT rollno, name, COUNT(*)
FROM mytable
GROUP BY rollno, name
You could also concat the two columns:
SELECT CONCAT(rollno, '-', name), COUNT(*)
FROM mytable
GROUP BY CONCAT(rollno, '-', name)

pl/sql query to remove duplicates and replace the data

I have the following table:
data_id new_data_id first_name last_name
1 john smith
2 john smith
3 john smith
4 jeff louis
5 jeff louis
6 jeff louis
The above table has duplicate first and last names, and the data_id is different for all of them. In order to remove these duplicates, I would need to write a SQL query to replace the highest data_id in new_data_id column. My output would look something like this:
data_id new_data_id first_name last_name
1 3 john smith
2 3 john smith
3 3 john smith
4 6 jeff louis
5 6 jeff louis
6 6 jeff louis
How would I do this?
What you're looking for is an Oracle analytic function.
The aggregate function MAX can be used to select the highest data_id from your entire resultset, but that's not exactly what you need. Instead, use its alter ego, the MAX analytic function like so:
SELECT
data_id,
MAX(data_id) OVER (PARTITION BY first_name, last_name) AS new_data_id,
first_name,
last_name
FROM employees
ORDER BY data_id
This works by "partitioning" your resultset by first_name and last_name, and then it performs the given function within that subset.
Good luck!
Here's a fiddle: http://sqlfiddle.com/#!4/48b29/4
More info can be found here:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions004.htm#SQLRF06174
If you need a change in place, a correlated update is probably the simplest way to write that:
UPDATE T
SET "new_data_id" =
(SELECT MAX("data_id") FROM T T2
WHERE T2."first_name" = T."first_name"
AND T2."last_name" = T."last_name")
See http://sqlfiddle.com/#!4/51a69/1

Should I Use a Self-Join

If I have a table...
ID Name Manager
0 Joe Sue
1 Jake Tom
0 Joe Tom
2 Larry Red
2 Larry Paul
1 Jake Paul
I want the output to be....
ID Name Manager1 Manager2
0 Joe Sue Tom
1 Jake Tom Paul
2 Larry Red Paul
Thanks...
If I have understood your request properly, yes, something like would produce the results you are looking for.
SELECT
t1.Name Name,
t1.Manager Manager1,
t2.Manager Manager2
FROM
Table t1
inner join Table t2 on t1.Manager = t2.Name
Of course a foreign key back to the index column would be preferential to strong comparisons for performance.
Yeah, if your table was called 'Managers':
SELECT Mgr1.ID,Mgr1.Name,Mgr1.Manager,Mgr2.Manager
FROM Managers AS Mgr1
LEFT JOIN Managers AS Mgr2
ON Mgr1.ID=Mgr2.ID
If your keeping the tables a join would be best.
If you hate joins, you could combine the max and min managers, and even then it would work if there is always 2 managers and they can't have the same name.
The below should work if I remember how to join up 2 queries correctly. but i would advise to see if it is possible to rework your table, have a separate table linking people to each other in a manager employee relation.
SELECT DISTINCT
F.ID, F.Name, S.Manager, F.Manager
FROM
(SELECT
ID, Name, MIN(manager) manager
FROM Managers
GROUP BY ID, Name) F,
(SELECT
ID, Name, MAX(manager) manager
FROM Managers
GROUP BY ID, Name) S
WHERE
F.ID = S.ID
AND S.Manager <> F.Manager
AND F.ID < S.ID

Select query which returns exect no of rows as compare in values of sub query

I have got a table named student. I have written this query:
select * From student where sname in ('rajesh','rohit','rajesh')
In the above query it's returning me two records; one matching 'rajesh' and another matching: 'rohit'.
But i want there to be 3 records: 2 for 'rajesh' and 1 for 'rohit'.
Please provide me some solution or tell me where i am missing.
NOTE: the count of result of sub query is not fix there can be many words there some distinct and some multiple occurrence .
Thanks
Your requirements are not clear, and I'll try to explain why.
Let's define table students
ID FirstName LastName
1 John Smith
2 Mike Smith
3 Ben Bray
4 John Bray
5 John Smith
6 Bill Lynch
7 Bill Smith
Query with WHERE clause:
FirstName in ('Mike', 'Ben', 'Mike')
will return 2 rows only, because it could be rewritten as:
FirstName='Mike' or FirstName='Ben' or FirstName='Mike'
WHERE is filtering clause that just says if existing row satisfy given conditions or not (for each of rows created by FROM clause.
Let's say we have subquery that returns any number of non distinct FirstNames
In case if SQ contains 'Mike', 'Ben', 'Mike' using inner join you can get those 3 rows without problem
Select ST.* from Students ST
Inner Join (Select name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
Result will be:
ID FirstName LastName
2 Mike Smith
2 Mike Smith
3 Ben Bray
Note data are not ordered by order of names returning by SQ. If you want that, SQ should return some ordering number, eg.:
Ord Name
1. Mike
2. Ben
3. Mike
In that case query should be:
Select ST.* from Students ST
Inner Join (Select ord, name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
Order By SQ.ord
And result:
ID FirstName LastName
2 Mike Smith (1)
3 Ben Bray (2)
2 Mike Smith (3)
Now, let's se what will happen if subquery returns
Ord Name
1. Mike
2. Bill
3. Mike
You will end up with
ID FirstName LastName
2 Mike Smith (1)
6 Bill Lynch (2)
7 Bill Smith (2)
2 Mike Smith (3)
Even worse, if you have something like:
Ord Name
1. John
2. Bill
3. John
Result is:
ID FirstName LastName
1 John Smith (1)
4 John Bray (1)
5 John Smith (1)
6 Bill Lynch (2)
7 Bill Smith (2)
1 John Smith (3)
4 John Bray (3)
5 John Smith (3)
This is an complex situation, and you have to clarify precisely what requirement is.
If you need only one student with the same name, for each of rows in SQ, you can use something like SQL 2005+):
;With st1 as
(
Select Row_Number() over (Partition by SQ.ord Order By ID) as rowNum,
ST.ID,
ST.FirstName,
ST.LastName,
SQ.ord
from Students ST
Inner Join (Select ord, name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
)
Select ID, FirstName, LastName
From st1
Where rowNum=1 -- that was missing row, added later
Order By ord
It will return (for SQ values John, Bill, John)
ID FirstName LastName
1 John Smith (1)
6 Bill Lynch (2)
1 John Smith (3)
Note, numbers (1),(2),(3) are shown to display value of ord although they are not returned by query.
If you can split the where clause in your calling code, you could perform a UNION ALL on each clause.
SELECT * FROM Student WHERE sname = 'rajesh'
UNION ALL SELECT * FROM Student WHERE sname = 'rohit'
UNION ALL SELECT * FROM Student WHERE sname = 'rajesh'
Try using a JOIN:
SELECT ...
FROM Student s
INNER JOIN (
SELECT 'rajesh' AS sname
UNION ALL
SELECT 'rohit'
UNION ALL
SELECT 'rajesh') t ON s.sname = t.sname
just because you've got a criteria in there two times doesn't mean that it will return 1 result per criteria. SQL engines usually just use the unique criteria - thus, from your example, there will be 2 criteria in IN clause: 'rajesh','rohit'
WHY do you need to return 2 results? are there two rajesh in your table? they should BOTH return then. You don't need to ask for rajesh twice for that to happen. What does your data look like? What do you want to see returned?
Hi i am query just as you give above and it give me all data that matches in the condition of in clause. just like your post
select * from person
where personid in (
'Carson','Kim','Carson'
)
order by FirstName
and its give me all records which fulfill this Criteria