Display the 0 in PostgresSQL - postgresql

I'm trying Display the number of satellites per planet. Satellites with a radius of less than 500 km must be ignored and their matching planets must be displayed with a null number. Sort by number of satellites then by planet name.
SELECT planet.name, COUNT(CASE WHEN satellite.radius > 500
THEN 1 END) AS "number of satellites"
FROM planet
JOIN satellite
ON (satellite.id_planet = planet.id)
GROUP BY planet.name
ORDER BY "number of satellites", planet.name;
When I do that I got
name | number of satellites
---------+----------------------
Earth | 1
Neptune | 1
Jupiter | 4
Uranus | 4
Saturn | 5
But I'm supposed to have this :
planet | number of satellites
---------+----------------------
Mars | 0
Mercury | 0
Venus | 0
Earth | 1
Neptune | 1
Jupiter | 4
Uranus | 4
Saturn | 5
I don't understand why the Zero are not present

Related

Is there a way to select elements associated with checked items without using multiple SELECT statements?

I'm trying to make a query that selects the neighborhoods ids of places that only have all the transport checked in a checkbox list. For instance, if 'Bus' and 'Railway' are checked, it should give me 7,8, and if only 'Railway' is checked, it should give me 7,8,11. The 'transporte' table is like this
b_codigo | tipo_transporte
----------+-----------------
1 | Underground
1 | Bus
2 | Bus
2 | Underground
3 | Bus
3 | Underground
4 | Bus
4 | RENFE
4 | Underground
5 | RENFE
5 | Underground
5 | Bus
5 | Tram
6 | Bus
6 | Underground
7 | RENFE
7 | Underground
7 | Bus
7 | Railway (FGC)
8 | Underground
8 | Railway (FGC)
8 | Bus
9 | Underground
9 | Bus
10 | Underground
10 | Bus
11 | Railway (FGC)
11 | Underground
12 | Bus
I tried with a query of the form
SELECT DISTINCT b_codigo
FROM transporte
WHERE (b_codigo, 'checked1') IN (SELECT * FROM transporte)
AND (b_codigo, 'checked2') IN (SELECT * FROM transporte)
AND ...
and another of the form
SELECT b_codigo
FROM transporte
WHERE tipo_transporte = 'checked1'
INTERSECT
SELECT b_codigo
FROM transporte
WHERE tipo_transporte = 'checked2'
INTERSECT
...;
and both give me the same results, but I'm worried about the efficiency of this two queries.
Is there a way of doing the same query without using N SELECT statements with N the number of checked boxes?
One way to do it, is to use aggregation:
select b_codigo
from transporte
where tipo_transporte in ('Bus', 'Railway (FGC)')
group by b_codigo
having count(distinct tipo_transporte) = 2
The number to compare to with the HAVING clause, needs to match the number of elements for the IN clause.

How can I use PostGIS to select the average price of the closest X locations?

I would like to find the average price of gas for any given home. Here are my current tables.
home_id | geocoordinates
1 | 0101000020E61000005BB6D617097544
2 | 0101000020E61000005BB6D617097545
3 | 0101000020E61000005BB6D617097546
4 | 0101000020E61000005BB6D617097547
5 | 0101000020E61000005BB6D617097548
gas_price | geocoordinates
1 | 0101000020E61000005BB6D617097544
1 | 0101000020E61000005BB6D617097545
1 | 0101000020E61000005BB6D617097546
2 | 0101000020E61000005BB6D617097547
2 | 0101000020E61000005BB6D617097548
2 | 0101000020E61000005BB6D617097544
2 | 0101000020E61000005BB6D617097545
3 | 0101000020E61000005BB6D617097546
3 | 0101000020E61000005BB6D617097547
3 | 0101000020E61000005BB6D617097548
3 | 0101000020E61000005BB6D617097544
4 | 0101000020E61000005BB6D617097545
4 | 0101000020E61000005BB6D617097546
4 | 0101000020E61000005BB6D617097547
For each home, I would like to find the average gas price of the X closest gas_prices. Example if X=5:
home_id | average_of_closest_five_gas_prices
1 | 1.5
2 | 2.5
3 | 2.1
4 | 1.5
5 | 1.5
I figured it out for using one individual home_id but I'm struggling to figure out how to do it for all.
select avg(gas_price) from (
SELECT *
FROM gas_price
ORDER BY gas_price.geocoordinates <-> '0101000020E61000005BB6D617097544'
LIMIT 5
) as table_a
You can use lateral join to limit size of group in group by.
select home_id, avg(gas_price)
from home,
lateral (
select gas_price
from gas_price
order by gas_price.geocoordinates <-> home.geocoordinates
limit 5
) x
group by home_id;
Another option is to use window function: partition by home_id, order by distance and select only rows with row_number() <= 5.
select home_id, avg(gas_price)
from (
select row_number() over w as r, *
from home h, gas_price g
window w as (partition by home_id order by g.geocoordinates <-> h.geocoordinates)
) x
where r <= 5
group by home_id;

Find the proportion of each X consisting of Y in PostgreSQL?

I have a big database of Magic: the Gathering cards and decklists. The table of cards contains the type and converted mana cost of each card (among other things). The decks are stored using two tables: a table of the decks themselves called "decks", and a table called "deckmembers", in which each row contains the ID of a deck, the ID of a card contained in that deck, and the number of copies of that card that appear in the deck.
What I want is a view of this data in which the rows are:
deck: the ID of a deck
cmc: a converted mana cost appearing on at least one card in that deck
proportion: the percentage of the nonland cards in that deck that have that cmc
Or am I better off deriving this data in Python or R or something?
This question is conceptually similar, but no one has answered it.
EDIT:
Since you asked, here's some example data:
cards:
id | name | fulltype | cmc
----+---------------------+-----------------+-----
1 | "Ach! Hans, Run!" | Enchantment | 6
2 | 1996 World Champion | Summon _ Legend | 5
4 | AWOL | Instant | 3
5 | Abandon Hope | Sorcery | 2
6 | Abandon Reason | Instant | 3
decks:
id | name
----+-----------------
1 | RDW
2 | Red Deck Recall
3 | RDW
4 | Red Deck Wins
5 | Red Deck Wins
deckmembers:
deck | card | count
------+-------+-------
1 | 14031 | 1
1 | 15011 | 1
1 | 14263 | 1
1 | 12966 | 1
1 | 12536 | 1
Any deck will have many cards. Any card may appear in many decks. Each card has an integer from 0-12 associated it which is called its "converted mana cost" or CMC. That's all you need to know. Don't bother learning to play Magic on my account.
And what I want might look something like:
deck | cmc | perc
------+-------+-------
1 | 1 | 11
1 | 2 | 11
1 | 3 | 11
1 | 4 | 11
1 | 5 | 11
Where "perc" in the first row says that 11 percent of the cards in the deck with with the id 1 have cmc 1.
Solved it!
SELECT
d.id,
c.cmc,
(CAST(SUM(m.count) AS FLOAT) /
(SELECT
CAST(SUM(m1.count) AS FLOAT)
FROM deckmembers AS m1
JOIN cards AS c1 ON c1.id=m1.card
WHERE NOT m1.sideboard
AND c1.fulltype NOT LIKE '%Land%'
AND m1.deck=d.id)
) * 100 AS perc
FROM deckmembers AS m
JOIN decks AS d ON d.id=m.deck
JOIN cards AS c ON c.id=m.card
WHERE NOT m.sideboard
AND c.fulltype NOT LIKE '%Land%'
GROUP BY d.id, c.cmc;
I also posted a solution to the simpler version of the problem here.

BIRT How to correctly chart date time axis with sparse data

I have a query that returns a count of events on dates over the last year.
e.g.
|Date | ev_count|
------------+----------
|2015-09-23 | 12 |
|2016-01-01 | 56 |
|2016-01-15 | 34 |
|2016-04-08 | 65 |
| ...
I want to produce a graph (date on the X-axis and value on Y) that will either show values for all dates (0 when no data), or at least place the dates where there are values in a correctly scaled place for the date along the time axis.
My current graph has just the values one after another. I have previously used dimple for generating graphs, and if you tell it that it's a time axis, it automagically places dates correctly spaced.
This is what I get
|
| *
| *
| *
|*_______________
9 1 1 4
This is what I want to have
|
| *
| *
| *
|_________*________________________________________
0 0 1 1 1 0 0 0 0 .....
8 9 0 1 2 1 2 3 4
Is there a function/trick in BIRT that will allow me to fill in the gaps with 0 or position/scale the date somehow (e.g. based on a max/min)? Or do I have to join my data with a date generator query to fill in the gaps?

A query to Find average value for each ranges?

Here is my table
GID | Distance (KM) | Subdistance (KM) | Iri_avg
-------------------------------------------------
1 | 13.952 | 0 | 0.34
2 | 13.957 | 0.005 | 0.22
3 | 13.962 | 0.010 | 0.33
4 | 13.967 | 0.015 | 0.12
5 | 13.972 | 0.020 | 0.35
...
I would like to find AVG of Iri_avg for each ranges,
for example..
each 5 metre (by default)
each 10 metre
each 100 metre
each 500 metre
What is the PostgreSQL query to solve this problem ?
Your question is unclear. Your data has two distance columns, which one do you mean?
Here is an example of how to get averages based on the subdistance.
select floor(subdistance*1000)/5.0)*5.0 as lower_bound, avg(iri_avg) as avg_ari_avg
from t
group by floor(subdistance*1000)/5.0)*5.0
order by 1
The expression "floor(subdistance*1000)/5.0)*5.0" gets the closest 5 meter increment less than the value. You can replace the "5" with "10" or "100" for other binning.
This is meant as an illustration. It is unclear which column you want to bin, what you want to do about empty bins, and whether you are looking for all bin-widths in a single query versus the query to handle just one bin-width.