how to SQL query with conditioned distinct - sql

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)

Related

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

Printing names of pairs of cities where the first city's population is less than the other

Let's say we have one table City with the following fields.
CITY
ID....................int
Name.............char(20)
Population.......int
ID | Name | Population
1 | Tokyo | 200
2 | Houston | 300
3 | Manchester | 100
How do you query pairs of cities where first city's population is less than the second city and separated with a space? (population of name A < population of name B)
Expected result:
Manchester, Tokyo
Tokyo, Houston
I tried the following:
SELECT a.name, b.name
FROM CITY a,
CITY b
WHERE a.population < b.population AND a.population != b.population;
Well, presumably you need to concatenate the city names together. You are fetching the populations.
SELECT CONCAT_WS(' ', a.name, b.name)
FROM CITY a JOIN
CITY b
ON a.population < b.population;
CONCAT_WS() is a convenient function that concatenates values with a separator.
This condition is unnecessary: AND a.population != b.population

Reconciliation Automation Query

I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn

SQL: select values in table A which are not in table B (and the other way around)

I have a hypothetical Census information by areas (Districts) collected in two different years:
Year 1 Table
District | Name
----------------
1 | Paul
1 | John
2 | Max
2 | Aaron
3 | Michael
Year 2 Table
District | Name
1 | Paul
1 | John
1 | Michael
3 | Michael
I'd like two queries:
Query 1: List new people by District. Should return Michael in District 1
Query 2: List missed people by District. Should return Max and Aaron in District 2
I would do this using union all and aggregation. The following query returns the name/district combinations that appear only in one year, along with the specific year:
select district, name, min(yyyy)
from ((select 1 as yyyy, district, name from table1) union all
(select 2, district, name from table2)
) tt
group by district, name
having count(distinct yyyy) = 1;
Query 1 : List new people by District. Should return Michael in District 1
SELECT Name, District
FROM year2
WHERE (Name NOT IN
(SELECT Name
FROM year1
WHERE (District = year2.District)))
GROUP BY Name, District
Query 2: List missed people by District. Should return Max and Aaron in District 2
SELECT Name, District
FROM year1
WHERE (Name NOT IN
(SELECT Name
FROM year2
WHERE (District = District)))
GROUP BY Name, District
If further you need combined result just use union all

SQL problem - one name 2 address in the same table

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