Concatenating multiple results of a query in one row in Oracle - sql

I have 2 tables with one having a reference to the first by id
first table for example is customer having the fields
id firstname lastname
------ --------- ---------
1 john smith
2 jessica james
the second table for example is product having the fields
id customer_id product descr
------- ----------- --------- ------
1 1 ts Shirt
2 1 ti Tie
3 2 sk skrit
I need a query that will output the following
customer.firstname customer.lastname product_and_desc
------------------ ------------------ ---------------------
john smith ts-Shirt , ti-Tie
jessica james sk-skirt
with the product rows variable for each customer.
I appreciate you help :)
thanks,

You can use list_agg(). In your case:
select c.firstname, c.lastname,
list_agg(p.product||'-'||p.desc, ' , ') within group (order by p.id) as product_and_desc
from customer c join
product p
on c.id = p.customer_id
group by c.firstname, c.lastname;
I would suggest, though, that the second argument to list_agg() be ', ' rather than ' , '. The space before the comma looks a bit unusual.

select first_name,last_name,wm_concat(product||'-'||descr) as product_and_descr
from tbl1 ,tbl2 where tbl1.id=tbl2.customer_id
group by first_name,last_name;

Related

How to use 'Count', based on a particular column in SQL

I have a query and which give the count greater than 1, but what I expect is I need the result to be based on particular column(Rollno.) How to achieve it.
Table Studies
NAME RollNo DeptType InternalStaff_1 InternalStaff_2
----------- ----------- ----------- --------------- ---------------
Anu 5 CompSci Eve Antony
Joy 13 Architecture Elizabeth George
Adam 2 Mech Grady Lisa
Adam 2 Mech Grady Kim
Anu 5 CompSci Eve Antony
The below query gives me Count but not as expected
SELECT DISTINCT S.Name
, S.RollNo
, COUNT(S.RollNo) AS [Count]
, S.DeptType
, S.InternalStaff_1
, S.InternalStaff_2
FROM DataMining.dbo.Studies S
WHERE StartDate >= '20210325'--#StartDate
AND StartDate <= '20210407'--#EndDate
GROUP BY S.Name, S.RollNo, S.DeptType, S.InternalStaff_1, S.InternalStaff_2
HAVING COUNT(S.RollNo) > 1
ORDER BY RollNo
The query gave me the below result
NAME RollNo Count DeptType InternalStaff_1 InternalStaff_2
----------- ----------- ----------- ----------- --------------- ---------------
Anu 5 2 CompSci Eve Antony
But the expected result is
NAME RollNo Count DeptType InternalStaff_1 InternalStaff_2
----------- ----------- ----------- ----------- --------------- ---------------
Anu 5 2 CompSci Eve Antony
Adam 2 2 Mech Grady NULL
As you can see the expected result is having a different InternalStaff_2 name for Adam which is not considered on the present result.
May I know how to over come this?
Note: I need the results to be displayed based on Rollno but I also need the InternalStaff_2 to be included in the result.
Hmmm . . . If I understand correctly, you want NULL if the internal staff columns do not match. That would be:
SELECT S.Name, S.RollNo, COUNT(*) AS [Count], S.DeptType,
(CASE WHEN MIN(S.InternalStaff_1) = MAX(S.InternalStaff_1) THEN MIN(S.InternalStaff_1) END) as InternalStaff_1,
(CASE WHEN MIN(S.InternalStaff_2) = MAX(S.InternalStaff_2) THEN MIN(S.InternalStaff_2) END) as InternalStaff_2
FROM DataMining.dbo.Studies S
WHERE StartDate >= '20210325' AND --#StartDate
StartDate <= '20210407' --#EndDate
GROUP BY S.Name, S.RollNo, S.DeptType
HAVING COUNT(*) > 1
ORDER BY RollNo;
Here is a db<>fiddle that shows that this basically works.
like this?
I do not confirm your needs, but the internalstaff_2 column can refer to STRING_AGG() to replace the nested subquery in the following script.
SELECT DISTINCT S.Name
, S.RollNo
, COUNT(S.RollNo) AS [Count]
, S.DeptType
, S.InternalStaff_1
, (SELECT CASE WHEN COUNT(DISTINCT InternalStaff_2) = 1 THEN MIN(InternalStaff_2) ELSE null END
FROM #temp AS i
WHERE i.NAME = S.NAME and i.RollNo = S.RollNo and i.DeptType = S.DeptType and i.InternalStaff_1 = S.InternalStaff_1) as InternalStaff_2
FROM #temp S
GROUP BY S.[Name], S.RollNo, S.DeptType, S.InternalStaff_1
HAVING COUNT(S.RollNo) > 1
ORDER BY RollNo

Keyword count in sqlite3

I have a database with two tables, 'person' and 'person_keyword'. I wanna print the number of keywords for each person. What I have tried until now is:
select person.name, keyword from person JOIN person_keyword ON person.name=person_keyword.keyword
But this only gives:
name keyword
----- -----
JOHN A
JOHN AD
JOHN V
SAM DE
SAM AS
EVA AZ
EVA AS
EVA FQ
EVA MQ
My expected output looks like this:
Name keyword
----- -----
JOHN 3
SAM 2
EVA 4
How should I solve this?
You can use group by:
select p.name, count(*) as cnt
from person p
inner join person_keyword ok on p.name = pk.keyword
group by p.name
Note: unless you really want some filtering on person, you could very well get that result directly from person_keyword:
select keyword as name, count(*) as cnt
from person_keyword
group by keyword

Create view by joining three tables in SQL

I have three tables STUDENTS, SUBJECTS, RANK ,with data as -
1) STUDENTS [NAME(Primary)]
NAME
--------
Alex
Greg
2) SUBJECTS [ID(Primary)]:
ID
--------
100
101
102
3) RANK [SEQ(Primary), NAME, ID, RANK]
SEQ NAME ID RANK
------ ------- ------ ------
1 Alex 100 A
2 Greg 100 A
3 Greg 101 B
I want to create a view that should display data as
NAME ID RANK
------- ------ ------
Alex 100 A
Alex 101 Z
Alex 102 Z
Greg 100 A
Greg 101 B
Greg 102 Z
So, for every student and for every subject, the View should display the RANK if present in RANK table, else replace the NULL with 'Z'.
I'm a newbie to SQL. So any help in forming the query would be deeply appreciated!
cross join student and subject then left outer join the result with rank to get ranks for all (student, subject) combination. selecting column with NVL OR COALESCE will replace NULL with 'z'.
SELECT st.name,
su.id,
NVL(ra.rank,'Z') Rank, --COALESCE(ra.rank,'Z') Rank
FROM student st
CROSS JOIN subject su
LEFT OUTER JOIN rank ra
ON ra.name = st.name
AND ra.id = su.id
ORDER BY st.name,su.id
Note : ORDER BY can be removed from above query if you don't need.
fiddle
SELECT r.NAME, r.ID, NVL(r.RANK, 'Z')
FROM RANK r, studendts st, SUBJECTS su
WHERE st. NAME = r. NAME
AND su.ID = r.ID
ORDER BY 1,2,3

SQL Pivot with String

I have two tables in SQL Server: Customer and Address
Customer Table:
CustomerID FirstName LastName
----------- ---------- ----------
1 Andrew Jackson
2 George Washington
Address Table:
AddressID CustomerID AddressType City
----------- ----------- ----------- ----------
1 1 Home Waxhaw
2 1 Office Nashville
3 2 Home Philadelphia
This is the output that I need:
CustomerID Firstname HomeCity OfficeCity
----------- ---------- ---------- ----------
1 Andrew Waxhaw Nashville
2 George Philadelphia Null
This is my query, but not getting the right result:
SELECT CustomerID, Firstname, HOme as HomeCity, Office as OfficeCity FROM
(SELECT C.CustomerID, C.FirstName, A.AddressID, A.AddressType, A.City
FROM Customer C, Address A
WHERE C.CustomerID = A.CustomerID)as P
PIVOT (MAX(city) FOR AddressType in ([Home],[Office])) as PVT
This is the result that I am getting:
CustomerID Firstname HomeCity OfficeCity
----------- ---------- ---------- ----------
1 Andrew Waxhaw NULL
1 Andrew NULL Nashville
2 George Philadelphia Null
As you can see Customer 1 is showing up twice in the final result. Is it possible to get only one row per customer?
I looked up this example, but didn't help:http://stackoverflow.com/questions/6267660/sql-query-to-convert-rows-into-columns
Thanks
It is giving this row because you have AddressID in the select list for you subquery "P". So even though you don't have AddressID in you top level select this, the PIVOT function is still grouping by it. You need to change this to:
SELECT CustomerID, Firstname, Home as HomeCity, Office as OfficeCity
FROM ( SELECT C.CustomerID, C.FirstName, A.AddressType, A.City
FROM #Customer C, #Address A
WHERE C.CustomerID = A.CustomerID
) AS P
PIVOT
( MAX(city)
FOR AddressType in ([Home],[Office])
) AS PVT
Although I would be inclined to use an explicit INNER JOIN rather than an implicit join between customer and Address.
I would write it like this instead:
SELECT C.CustomerID, C.Firstname,
Home.City as HomeCity,
Office.City as OfficeCity
FROM Customer C
LEFT JOIN Address Home
on Home.CustomerID = C.CustomerID and Home.AddressType = 'Home'
LEFT JOIN Address Office
on Office.CustomerID = C.CustomerID and Office.AddressType = 'Office'

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