SQL problem - one name 2 address in the same table - sql

CName | AddressLine
-------------------------------
John Smith | 123 Nowheresville
Jane Doe | 456 Evergreen Terrace
John Smith | 999 Somewhereelse
Joe Bloggs | 1 Second Ave
If i have this table is possible to do a select to put like this
CNAME | Address1 | Address2
John Smith | 123 Nowheresville | 999 Somewhereelse
I'm using oracle

It is considered a bad design (inefficient memory usage) to add a new column for appearance of duplications in just some rows . Maybe you should consider using inner-join and a separate table for the address column!

As your table stands, you cannot use a simple self-join to reduce this to a single line. You can bring back rows that have all of the addresses (so long as you hard-code for a particular maximum number of addresses), but you will always have the same number of rows as there are addresses for a given user (unless you have a way of identifying a single address as "primary").
In order to reduce your result set to a single line, you'll have to provide some way of marking a "first" address. With SQL Server (or similar professional-grade RDBM's), you could use a common table expression with ranking/row numbering functions to do this:
with Addresses as
(select
CName,
AddressLine,
row_number() over (partition by CName order by AddressLine) as RowNum
from YourTable)
select
a1.CName,
a1.AddressLine as Address1,
a2.AddressLine as Address2,
a3.AddressLine as Address3
from Addresses a1
left join Addresses a2 on a2.CName = a1.CName and a2.RowNum = 2
left join Addresses a3 on a3.CName = a1.CName and a3.RowNum = 3
where a1.RowNum = 1

temp = your table name
select distinct cname, addressline as [address1],
(
ISNULL((select addressline from temp where cname = t.cname and addressline != t.addressline), '')
) as address2
from
temp t

The problem is resolve, Frank Kulash in oracle forum solved the problem
Here is the solution:
WITH got_r_num AS
(
SELECT cname, addressline
, ROW_NUMBER () OVER ( PARTITION BY cname
ORDER BY addressline
) AS r_num
FROM table_x
-- WHERE ... -- If you need any filtering, put it here
)
SELECT cname
, MIN (CASE WHEN r_num = 1 THEN addressline END) AS addressline1
, MIN (CASE WHEN r_num = 2 THEN addressline END) AS addressline2
FROM got_r_num
GROUP BY cname
Tanks to all for the help

Related

How to check how many times some values are duplicated?

I have table like below:
city | segment
------------------
London | A
London | B
New York | A
Berlin | B
Barcelona | C
Barcelona | H
Barcelona | E
Each city should have only one segment, but as you can see there are two cities (London and Barcelona) that have more than one segment.
It is essential that in result table I need only these cities which have > 1 segmnet
As a result I need somethig like below:
city - city based on table above
no_segments - number of segments which have defined city based on table above
segments - segments of defined city based on table above
city
no_segments
segments
London
2
A
B
Barcelona
3
C
H
E
How can I do that in Oracle?
You can use COUNT(*) OVER ()(in order to get number of segments) and ROW_NUMBER()(in order to prepare the results those will be conditionally displayed) analytic functions such as
WITH t1 AS
(
SELECT city,
segment,
COUNT(*) OVER (PARTITION BY city) AS no_segments,
ROW_NUMBER() OVER (PARTITION BY city ORDER BY segment) rn
FROM t
)
SELECT DECODE(rn,1,city) AS city,
DECODE(rn,1,no_segments) AS no_segments,
segment
FROM t1
WHERE no_segments > 1
ORDER BY t1.city, segment
Demo
Another way to do this is:
SELECT NULLIF(CITY, PREV_CITY) AS CITY,
SEGMENT
FROM (SELECT CITY,
LAG(CITY) OVER (ORDER BY CITY DESC) AS PREV_CITY,
SEGMENT,
COUNT(SEGMENT) OVER (PARTITION BY CITY) AS CITY_SEGMENT_COUNT
FROM CITY_SEGMENTS)
WHERE CITY_SEGMENT_COUNT > 1
Using LAG() to determine the "previous" CITY allows us to directly compare the CITY values, which in my mind is clearer that using ROW_NUMBER = 1.
db<>fiddle here
;with cte as (
Select city, count(seg) as cntseg
From table1
Group by city having count(seg) > 1
)
Select a.city, b.cntseg, a.seg
From table1 as a join cte as b
On a.city = b.city

SQL Combine duplicate rows while concatenating one column

I have a table (example) of orders show below. The orders are coming in with multiple rows that are duplicated for all columns except for the product name. We want to combine the product name into a comma delimited string with double quotes. I would like to create a select query to return the output format shown below.
INPUT
Name address city zip product name
-----------------------------------------------------------------
John Smith 123 e Test Drive Phoenix 85045 Eureka Copper Canyon, LX 4-Person Tent
John Smith 123 e Test Drive Phoenix 85045 The North Face Sequoia 4 Tent with Footprint
Tom Test 567 n desert lane Tempe 86081 Cannondale Trail 5 Bike - 2021
OUTPUT
Name address city zip product name
------------------------------------------------------------------
John Smith 123 e Test Drive Phoenix 85045 "Eureka Copper Canyon, LX 4-Person Tent", "The
North Face Sequoia 4 Tent with Footprint"
Tom Test 567 n desert lane Tempe 86081 Cannondale Trail 5 Bike - 2021
You can have List_AGG() OR GROUP_CONCAT and then join the results back to original table. Then you can remove duplicates using row_number which will create a same rank
if data is same
WITH ALL_DATA AS (
SELECT * FROM TABLE
),
LIST_OF_ITEMS_PER_PRODUCT AS (
SELECT
ALL_DATA.NAME,
LIST_AGG(ALL_DATA.PRODUCT_NAME , ",") AS ALL_PRODUCTS_PER_PERSON
-- IF YOUR SQL DON'T SUPPORT LIST_AGG() THEN USE GROUP_CONCAT INSTEAD
FROM
ALL_DATA
GROUP BY 1
),
LIST_ADDED AS (
SELECT
ALL_DATA.*,
LIST_OF_ITEMS_PER_PRODUCT.ALL_PRODUCTS_PER_PERSON
FROM
ALL_DATA
LEFT JOIN LIST_OF_ITEMS_PER_PRODUCT
ON ALL_DATA.NAME = LIST_OF_ITEMS_PER_PRODUCT.NAME
),
ADDING_ROW_NUMBER AS (
SELECT
* ,
ROW_NUMBER() over (partition by list_added.NAME, ADDRESS, CITY, ZIP ORDER BY NAME) AS ROW_NUMBER_
FROM LIST_ADDED
)
SELECT
* FROM
ADDING_ROW_NUMBER
WHERE ROW_NUMBER_ = 1

how to SQL query with conditioned distinct

Simple Database:
street | age
1st st | 2
2nd st | 3
3rd st | 4
3rd st | 2
I'd like to build a query that'll return the DISTINCT street names, but only for those households where no one is over 3.
so that result would be:
street | age
1st st | 2
2nd st | 3
How do I do that? I know of DISTINCT, but now how to conditionalize it for all the records that match the DISTINCT
Suppose the name of the table is 'tab'. You can then try:
select distinct street from tab where street not in (select street from tab where age>3);
I have created a sql fiddle where you can view the result:
http://sqlfiddle.com/#!9/2c513d/2
Distinct street names for households where no one is over 3:
SELECT street
FROM table
GROUP BY street
HAVING COUNT(1) <= 3
SELECT DISTINCT street
FROM table
WHERE NOT(age>3)
USE GROUP BY
Select Street
from yourtable
group by street
Having sum(age)<=3
Another way this could be achived with a use of NOT EXISTS
SELECT *
FROM yourtable a
WHERE NOT EXISTS
(SELECT street
FROM yourtable b
WHERE age > 3
AND a.street = b.street)

Order by Lastname and ID

I have two DB tables
FAMILY
------
family_id (PK)
address
....
PERSON
-----
person_id (PK)
lastname
birthday
family_id (FK)
family_role (numeric >1 male, 2 female, 3 male(child), 4 female(child)
....
I want to create an alphabetic family list, in which the lastname of the oldest person must be leading and ordered by the FAMILY_ROLE. I was trying something like:
select *
from person, family
where person.family_id = family.family_id
order by lastname, family_role
Now this is not working, because last names in the same family doesn't have to be the same. So this is working
select *
from person, family
where person.family_id = family.family_id
order by family_id, family_role
But that doesn't give me an alphabetic list.
The output must be something like:
Test street 1 - New York (family_id = 100)
John Bla (family_id = 100 | person_id =10 | family_role=1)
Sara Bla (family_id = 100 | person_id =13 | family_role=2)
----
Apple street 1 - New York (family_id = 45)
Rick Cha (family_id = 45 | person_id =1 | family_role=1)
Lin Cha (family_id = 45 | person_id =5 | family_role=2)
Jean App (family_id = 45 | person_id =3 | family_role=4)
----
Cherry street 114 - New York (family_id = 23)
Becky Cha (family_id = 23 | person_id =122 | family_role=2)
----
Can someone help me? Database version MSSQL 2008.
Also please keep in mind that people can have the same last name, but belong in a different family (see the Cha families in the output example).
Thanks!
You need a way to associate the last name of the oldest person in a family with everyone in the family. You can use ROW_NUMBER() in a cte/subquery for this:
;with cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY Family_ID ORDER BY Age DESC) AS RN
FROM Person
)
SELECT p.*,f.*
FROM person p
JOIN family f
ON p.family_id = f.family_id
JOIN cte
ON p.family_id = cte.Family_ID
AND cte.RN = 1
ORDER BY cte.lastname
The ROW_NUMBER() function assigns a number to each row. PARTITION BY is optional, but used to start the numbering over for each value in that group, ie: if you PARTITION BY Family_ID then for each unique Family_ID value the numbering would start over at 1. ORDER BY of course is used to define how the counting should go, and is required in the ROW_NUMBER() function.
So the cte/subquery gives you a way to see who the oldest person is and access their last name in one step, then you can JOIN to this to use in your ORDER BY.
Note: Old-style joins should also be avoided, and so I updated that as well, and I'm assuming you have an Age field in your Person table to determine who the oldest is, the cte may require updating based on actual table structure.
Well, you have to decide how you are going to choose which family member is going to determine the alphabetical placement of the family. For example if family #100 has Jon Doe and Jane Smith, will it come in the Ds alphabetically or the Ss?
You could write the query like this
SELECT f.*,p.*,A.FamilyNameOrderKey FROM
(
SELECT
Min(lastname) As FamilyNameOrderKey, Family_id
FROM
person
Group by Family_id
) As A
INNER JOIN
family f
ON
A.family_id = f.family_id
INNER JOIN
people p
ON
p.family_id = f.family_id
)
Order by A.FamilyNameOrderKey
This will sort by the last name of the alphabetically first last name in each family

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