I'm doing SQL Zoo and go stuck with this question:
List each continent and the name of the country that comes first alphabetically.
Here's a sample of the table:
+-------------+-----------+---------+
| name | continent | area |
+-------------+-----------+---------+
| Afghanistan | Asia | 652230 |
| Albania | Europe | 2831741 |
| Algeria | Africa | 28748 |
| ... | ... | ... |
+-------------+-----------+---------+
the use of ALL in this case. Here's the solution:
SELECT continent, name
FROM world x
WHERE name <= ALL (
SELECT name FROM world y
WHERE x.continent= y.continent)
Is this saying to find the name where name is "smaller" then all of the values found in matching continents?
Does this not answer the question?
select continent
, min(name) "First Alphabetical"
from world
group by continent
Related
Sorry if this has been asked before, I couldn't find it.
I have census population dataframe that contains the population of each county in the US.
The relevant part of df looks like:
+----+--------+---------+----------------------------+---------------+
| | REGION | STNAME | CTYNAME | CENSUS2010POP |
+----+--------+---------+----------------------------+---------------+
| 1 | 3 | Alabama | Autauga County | 54571 |
+----+--------+---------+----------------------------+---------------+
| 2 | 3 | Alabama | Baldwin County | 182265 |
+----+--------+---------+----------------------------+---------------+
| 69 | 4 | Alaska | Aleutians East Borough | 3141 |
+----+--------+---------+----------------------------+---------------+
| 70 | 4 | Alaska | Aleutians West Census Area | 5561 |
+----+--------+---------+----------------------------+---------------+
How I can get the np.std of the states population (sum of counties' population) for each of the four regions in the US without modifying the df?
You can use transform:
df['std_col'] = df.groupby('STNAME')['CENSUS2010POP'].transform("std")
IIUC, if you want sum of counties, you do:
state_pop = df.groupby('STNAME')['CTYNAME'].nunique().apply(np.std)
You can also directly use the standard deviation method std()
new_df=df.groupby(['REGION'])[['CENSUS2010POP']].std()
I'm learning nested select and I've encountered a problem with AS operator within the second (i.e. nested select).
Please have a look at the following table (truncated):
+-------------+-----------+---------+------------+--------------+
| name | continent | area | population | gdp |
+-------------+-----------+---------+------------+--------------+
| Afghanistan | Asia | 652230 | 25500100 | 20343000000 |
| Albania | Europe | 28748 | 2831741 | 12960000000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000000 |
| Andorra | Europe | 468 | 78115 | 3712000000 |
| Angola | Africa | 1246700 | 20609294 | 100990000000 |
+-------------+-----------+---------+------------+--------------+
The aim is to show the countries in Europe with a per capita GDP greater than that of United Kingdom's. (Per capita GDP is the gdp/population).
The following query is correct in terms of syntax but it will not give the correct result as it selects gdp instead of gdp/population:
SELECT name
FROM world
WHERE gdp/population >
(SELECT gdp
FROM world
WHERE name = 'United Kingdom')
AND continent = 'Europe';
One solution to correct this would be using gdp/population instead of gdp in nested select but the resulting query would be incorrect in terms of syntax. Why? I use MariaDB but I'd like the query to be not dependent on DBMS provider.
SELECT name
FROM world
WHERE gdp/population >
(SELECT gdp AS gdp/population
FROM world
WHERE name = 'United Kingdom')
AND continent = 'Europe';
AS syntax is
SELECT expression AS ALIAS
So you got it the wrong way round, and the alias you are defining contains an illegal character (/). An alias is not required in this case, so you can simply do:
SELECT name
FROM world
WHERE gdp/population >
(SELECT gdp/population
FROM world
WHERE name = 'United Kingdom')
AND continent = 'Europe';
Input Table : Regions
+---------------+---------------+---------- +-----------+
| Child | Parent | Level | levelname|
+---------------+---------------+---------- +-----------+
| All Region | All Region | 1 | national |
| Africa Region | All Region | 2 | region |
| America | All Region | 2 | region |
| Asia | All Region | 2 | region |
| Europe Region | All Region | 2 | region |
| Africa | Africa Region | 3 | Subregion |
| Asia Pacific | Asia | 3 | Subregion |
| Europe | Europe Region | 3 | Subregion |
| North America | America | 3 | Subregion |
| South America | America | 3 | Subregion |
| Argentina | South America | 4 | Country |
| Australia | Asia Pacific | 4 | Country |
| Pakistan | Asia Pacific | 4 | Country |
| South Africa | Africa | 4 | Country |
| Tunisia | Africa | 4 | Country |
| Uruguay | South America | 4 | Country |
+-------------------------------------------------------+
Here , regions are of 4 levels
All region
Region
Sub Region
Country
they have 0,1,2 and 3 ancestors,such as a country has subregion,region and allregion as ancestors ,suppose we give "Uruguay" ,then output will be South America, America , All Region.
Now, I need a query for this table,which will retrieve all ancestors for a given "child"
Your best bet is a recursive CTE:
With recRegions AS
(
/*Recursive Seed*/
SELECT
Child,
Parent,
Level,
0 as Depth,
CAST(Child as VARCHAR(5000)) as Path
FROM
Regions
WHERE
Child=<WhateverChildYouAreWanting>
UNION ALL
/*Recursive Term*/
SELECT
Regions.Child,
Regions.Parent,
Region.Level,
recRegions.Depth + 1,
recRegions.Path || '>' || Region.Child
FROM
recRegions
INNER JOIN Regions on
recRegions.parent = Regions.Child
Where recRegions.Depth < 10
)
Select Parent as Ancestors FROM recRegions;
Recursive queries can be a little tricky to wrap your head around at first, but if you break up the pieces of it, it makes sense:
Recursive Seed - This is the part where we get the first term we are after. In your case, we just want the record where the Child is the country you are wanting to query.
Recursive Term - This is the part where the query refers back to itself. It joins the recursive CTE recRegions to your Region table, connecting the child to the parent. The DB will hit this recursive term until no more records come back, which means we've climbed all the way up your hierarchy.
The final select statement just pulls back the records from your recursive query. You wanted all the ancestors, so that would be all of the Parent field records.
Generally when you see a table with a layout child | parent | attributes | of | that | relationship you can turn to the super powerful recursive CTE to make quick sense out of it all.
As #dnoeth mentioned in your Q's comments, you could also join Regions table to itself 4 times since your hierarchy seems to be only 4 deep. A recursive query doesn't care about depth though, so if you add more depth to your hierarchy, you won't have to edit your SQL to pull the ancestors.
Updated to add a "Depth" field to track recursions and stop after 10. Also added a "Path" field to track the hierarchy as it's built up from the Child. If you have an issue with your hierarchy cycling (a child reporting to a parent that reports to the child causing an endless loop) then you can use the following SQL statement instead of the SELECT parent FROM version above:
SELECT * FROM recRegions;
Now you will see Path and Depth of each node of your hierarchy so you can fix your data, or the recursive CTE to avoid the cycling.
I have three tables like this:
Person table:
person_id | name | dob
--------------------------------
1 | Naveed | 1988
2 | Ali | 1985
3 | Khan | 1987
4 | Rizwan | 1984
Address table:
address_id | street | city | state | country
----------------------------------------------------
1 | MAJ Road | Karachi | Sindh | Pakistan
2 | ABC Road | Multan | Punjab | Pakistan
3 | XYZ Road | Riyadh | SA | SA
Person_Address table:
person_id | address_id
----------------------
1 | 1
2 | 2
3 | 3
Now I want to get all records of Person_Address table but also with their person and address records like this by one query:
person_id| name | dob | address_id | street | city | state | country
----------------------------------------------------------------------------------
1 | Naveed | 1988 | 1 | MAJ Road | Karachi | Sindh | Pakistan
2 | Ali | 1985 | 2 | ABC Road | Multan | Punjab | Pakistan
3 | Khan | 1987 | 3 | XYZ Road | Riyadh | SA | SA
How it is possible using zend? Thanks
The reference guide is the best starting point to learn about Zend_Db_Select. Along with my example below, of course:
//$db is an instance of Zend_Db_Adapter_Abstract
$select = $db->select();
$select->from(array('p' => 'person'), array('person_id', 'name', 'dob'))
->join(array('pa' => 'Person_Address'), 'pa.person_id = p.person_id', array())
->join(array('a' => 'Address'), 'a.address_id = pa.address_id', array('address_id', 'street', 'city', 'state', 'country'));
It's then as simple as this to fetch a row:
$db->fetchRow($select);
In debugging Zend_Db_Select there's a clever trick you can use - simply print the select object, which in turn invokes the toString method to produce SQl:
echo $select; //prints SQL
I'm not sure if you're looking for SQL to do the above, or code using Zend's facilities. Given the presence of "sql" and "joins" in the tags, here's the SQL you'd need:
SELECT p.person_id, p.name, p.dob, a.address_id, street, city, state, country
FROM person p
INNER JOIN Person_Address pa ON pa.person_id = p.person_id
INNER JOIN Address a ON a.address_id = pa.address_id
Bear in mind that the Person_Address tells us that there's a many-to-many relationship between a Person and an Address. Many Persons may share an Address, and a Person may have more than one address.
The SQL above will show ALL such relationships. So if Naveed has two Address records, you will have two rows in the result set with person_id = 1.
I'm using the MySQL WORLD database.
For each Continent, I want to return the Name of the country with the largest population.
I was able to come up with a query that works. Trying to find another query that uses join only and avoid the subquery.
Is there a way to write this query using JOIN?
SELECT Continent, Name
FROM Country c1
WHERE Population >= ALL (SELECT Population FROM Country c2 WHERE c1.continent = c2.continent);
+---------------+----------------------------------------------+
| Continent | Nanme |
+---------------+----------------------------------------------+
| Oceania | Australia |
| South America | Brazil |
| Asia | China |
| Africa | Nigeria |
| Europe | Russian Federation |
| North America | United States |
| Antarctica | Antarctica |
| Antarctica | Bouvet Island |
| Antarctica | South Georgia and the South Sandwich Islands |
| Antarctica | Heard Island and McDonald Islands |
| Antarctica | French Southern territories |
+---------------+----------------------------------------------+
11 rows in set (0.14 sec)
This is the "greatest-n-per-group" problem that comes up frequently on StackOverflow.
SELECT c1.Continent, c1.Name
FROM Country c1
LEFT OUTER JOIN Country c2
ON (c1.continent = c2.continent AND c1.Population < c2.Population)
WHERE c2.continent IS NULL;
Explanation: do a join looking for a country c2 that has the same continent and a greater population. If you can't find one (which is indicated by the outer join returning NULL for all columns of c2) then c1 must be the country with the highest population on that continent.
Note that this can find more than one country per continent, if there's a tie for the #1 position. In other words, there could be two countries for which no third country exists with a greater population.