Move the extra entry to a new row in SQL Server - sql

I have a table.
Country| Continent| City
----------------------------
USA Americas [{1,New York}]
Chile Americas [{2,Santiago}]
England Europe [{3,London},{4,Bristol}]
I want to move the extra entry to a new row in sql server. And the output needs to look like this.
----------------------------
Country| Continent| City
----------------------------
USA Americas [{1,New York}]
Chile Americas [{2,Santiago}]
England Europe [{3,London}]
England Europe [{4,Bristol}]

Try this
;WITH CTE(Country, Continent, City)
AS
(
SELECT 'USA' ,'Americas' ,'[{1,New York}]' UNION ALL
SELECT 'Chile' ,'Americas' ,'[{2,Santiago}]' UNION ALL
SELECT 'England','Europe' ,'[{3,London},{4,Bristol}]'
)
SELECT Country,
Continent,
QUOTENAME(IIF(RIGHT(Split.a.value('.','nvarchar(1000)'),1)<>'}',Split.a.value('.','nvarchar(1000)')+'}' ,Split.a.value('.','nvarchar(1000)')))
AS City
FROM
(
SELECT Country,Continent,CAST('<S>'+ REPLACE(REPLACE(REPLACE(City,'[',''),']',''),'},','</S><S>' )+'</S>' AS XML) AS City
FROM CTE
)AS A
CROSS APPLY City.nodes('S') AS Split(a)
Demo Result : http://rextester.com/AWWN39720

Related

Sum of column depending on values

Can you guys let me know how to make a query that output the sum of amount based on column values(order, Continent and Country)? Also, I want to show all Continent values as unique value (North America)
Example table,
ID Code Continent Country amount
----------------------------------------------------
1 1 North America NULL NULL
2 1 America USA 10
3 1 NA USA 10
4 1 Unknown USA 10
5 2 North America NULL NULL
6 2 America Canada 15
7 2 NA Canada 15
8 2 Unknown Canada 15
9 3 North America NULL NULL
10 3 America Mexico 20
11 3 NA Mexico 20
12 3 Unknown Mexico 20
Output
ID Code Continent Country SumAmount
----------------------------------------------
1 1 North America USA 30
2 2 North America Canada 45
3 3 North America Mexico 60
I have tried to approach it like
select ID, Code, case when Continent != 'North America' then Continent = 'North America' end as Continent, Country, sum(Amount) as SumAmount
from Table group by ID, Continent, Country
or maybe I need to make a query like this and work with this query below?
select ID, Code, Continent, Country, sum(Amount) as SumAmount
from Table where Continent !='North America'
But it is not working. How should I do this?
I appreciate for any other approaches. It would be better than mine
The awkward design here (relations with no real indication of such other than the shared Code column) is going to lead to suboptimal queries like this
DECLARE #ContinentToReport varchar(32) = 'North America';
;WITH x AS
(
SELECT Code FROM dbo.TableName
WHERE Continent = #ContinentToReport
AND Country IS NULL
)
SELECT ID = ROW_NUMBER() OVER (ORDER BY x.Code),
x.Code,
Continent = #ContinentToReport,
t.Country,
SumAmount = SUM(t.amount)
FROM dbo.TableName AS t
INNER JOIN x ON t.Code = x.Code
WHERE t.Country IS NOT NULL
GROUP BY x.Code, t.Country
ORDER BY x.Code;
Output (though I made a guess at what ID means and why it's different then the ID and the source, and I find the Continent column is kind of redundant since it will always be the same):
ID
Code
Continent
Country
SumAmount
1
1
North America
USA
30
2
2
North America
Canada
45
3
3
North America
Mexico
60
Example db<>fiddle
The simplest query which returns the correct result seems to be something like this
select row_number() over (order by Code) ID,
Code,
'North America' Continent,
Country,
sum(amount) SumAmount
from dbo.TableName
where Country is not null
group by Code, Country
order by Code;
dbFiddle

Ordering Query for Country & City data for the scenario given

My input data is below :
**Country city**
Australia Sydney
Australia melbourne
India Delhi
India Chennai
India Bangalore
Afghanistan Kabul
Output expected is:
Afghanistan
Kabul
Australia
melbourne
syndey
India
Bangalore
Chennai
Delhi
The data in both columns should be arranged alphabetically(both city level and country level) and result should be single column with above values. The country should be alphabetically ordered and the corresponding cities should go below them which should also be alphabetically ordered.
How can this be done without using an intermediate table in a single query?
You need a UNION ALL query to get one row per country and one row per city in your result:
select coalesce(city, country) as location
from
(
select distinct country, null as city from mytable
union all
select country, city from mytable
)
order by country, city nulls first;
This has a single table scan and also does not need to use UNION to get distinct results:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE cities ( Country, city ) AS
SELECT 'Australia', 'Sydney' FROM DUAL UNION ALL
SELECT 'Australia', 'melbourne' FROM DUAL UNION ALL
SELECT 'India', 'Delhi' FROM DUAL UNION ALL
SELECT 'India', 'Chennai' FROM DUAL UNION ALL
SELECT 'India', 'Bangalore' FROM DUAL UNION ALL
SELECT 'Afghanistan', 'Kabul' FROM DUAL;
Query 1:
SELECT value
FROM (
SELECT c.*,
country AS ctry,
ROW_NUMBER() OVER ( PARTITION BY Country ORDER BY city ) AS rn
FROM cities c
)
UNPIVOT( value FOR key IN ( Country AS 1, City AS 2 ) )
WHERE rn = 1 OR key = 2
ORDER BY ctry, rn, key
Results:
| VALUE |
|-------------|
| Afghanistan |
| Kabul |
| Australia |
| Sydney |
| melbourne |
| India |
| Bangalore |
| Chennai |
| Delhi |

Check for an entry in SQL Server

-----------------------
country | city | ids
-----------------------
India Mumbai 1
India Chennai 2
India Kolkata 3
---------------------
USA New York 2
USA Utah 3
---------------------
I have given a sample from a table. From the table, I am trying to query all the countries without id 1. I wrote this(Country was not included in the Where condition since it needs to apply to all the countries of the table).
Select * from Countries
WHERE id<>1
I got this.
-----------------------
country | city | ids
-----------------------
India Chennai 2
India Kolkata 3
---------------------
USA New York 2
USA Utah 3
---------------------
But I need the output to contain only USA(which does not have id=1). Is there any workaround for this?
SELECT * from Countries WHERE country not in
(SELECT country from Countries WHERE id=1)
use NOT EXISTS
Select *
from Countries c
where not exists
(
select *
from Countries x
where x.country = c.country
and x.id = 1
)
You need to group by Country like below :
SELECT C.Country
FROM City
WHERE C.Country NOT IN
(SELECT country FROM City WHERE id=1)
SQL Fiddle Demo
OR
SELECT
C.Country
FROM
City C
GROUP BY C.Country
HAVING C.Country NOT IN
(
SELECT Country FROM City WHERE Id =1
)
SQL Fiddle Demo

Using HAVING with GROUPING SETS

My sql string as below
SELECT Country, City, COUNT(*) AS [Count]
FROM CountriesAndCities
GROUP BY GROUPING SETS ( ( Country, City ), ( Country) )
ORDER BY Country, City
I am getting results as below
Country City CountryCount
---------- ---------- ------------
France NULL 4
France Paris 4
Spain NULL 6
Spain Barcelona 3
Spain Madrid 3
If country has got only one city record, can I get results as below with using HAVING
Country City CountryCount
---------- ---------- ------------
France Paris 4
Spain NULL 6
Spain Barcelona 3
Spain Madrid 3
SELECT Country, City, COUNT(*) AS [Count]
FROM CountriesAndCities
GROUP BY GROUPING SETS ( ( Country, City ), ( Country) )
HAVING GROUPING(City) = 0
OR COUNT(DISTINCT City) > 1
ORDER BY Country, City
GROUPING(City) = 0 if City one of the fields currently being grouped by.
Conversely, when GROUPING(City) = 1 then City is reported as NULL.
This means that we always include the rows where the City is mentioned (not NULL).
For the other rows, where GROUPING(City) = 1 aka City IS NULL, then we only include the row if more than one City has been aggregated in to the result.

SQL help with MAX query

I have a table of countries named bbc(name, region, area, population, gdp)
I want a table with the region, name and population of the largest ( most populated) countries by region. So far i've tried this:
SELECT region, name, MAX(population)
FROM bbc
GROUP BY region
It gave me an error message : ORA-00979: Not a GROUP BY Expression
I tried to change to GROUP BY region, name, but it doesn't give me the right table
You can use analytics for queries like that:
SELECT name, region, population
FROM (SELECT region, name, population
, MAX(population) OVER (PARTITION BY region) maxpop
FROM bbc)
WHERE population = maxpop;
The inline view gives you a table that looks like your base table, plus an extra column with the max population for the region. Your top-level select gives you the country, region and population of the largest country in each region.
To illustrate with a limited example:
SELECT * FROM bbc;
REGION NAME POPULATION
--------------- ------- ----------
North America USA 300000000
North America Canada 100000000
North America Mexico 50000000
South America Brazil 50000000
South America Argentina 40000000
South America Venezuela 20000000
Add the analytic function:
SELECT region, NAME, population
, MAX(population) OVER (PARTITION BY region) maxpop
FROM bbc;
REGION NAME POPULATION MAXPOP
--------------- ------- ---------- ----------
North America USA 300000000 300000000
North America Canada 100000000 300000000
North America Mexico 50000000 300000000
South America Brazil 50000000 50000000
South America Argentina 40000000 50000000
South America Venezuela 20000000 50000000
Then the finished product:
NAME REGION POPULATION
------- --------------- -----------
USA North America 300000000
Brazil South America 50000000
One more edit. You can avoid a nest select, but not a subquery:
SELECT NAME, region, population
FROM bbc
WHERE (region, population) IN
(SELECT region, MAX(population)
FROM bbc
group by region);
Here's the easiest and shortest way to do it, since Oracle has tuple testing, it can make the code shorter:
First, get the max population on each region:
SELECT region, MAX(population)
FROM bbc
GROUP BY region
Then test the countries against it:
select region, name, population
from bbc
where (region, population) in
(SELECT region, MAX(population)
FROM bbc
GROUP BY region)
order by region
If you want to support many RDBMS, use EXISTS:
select region, name, population
from bbc o
where exists
(SELECT null -- neutral. doesn't invoke Cargo Cult Programming ;-)
FROM bbc
WHERE region = o.region
GROUP BY region
HAVING o.population = MAX(population) )
order by region
Query tested here, both have similar output: http://sqlzoo.net/0.htm
http://www.ienablemuch.com/2010/05/why-is-exists-select-1-cargo-cult.html
In the vast majority of vases, the ORA-00979 error is caused because a non-aggregated column is not included in the GROUP BY clause. In this case you need to include name as well in your GROUP BY clause. Also, you should not be calling the MAX function in your FROM statement.
SELECT region, name, MAX(population)
FROM bbc
GROUP BY region, name