Add/Remove both duplicate results from SQL query based on flag - sql

I have a table that includes data where I want to grab all rows with a flag of zero as well as rows with a positive flag of my choosing, then I would like it to remove all data from the query that contains the same data, but has a negative flag value. Currently I am handling all of this in my front end by grabbing all my 0 and positive flag values, then grabbing all my negative values and removing them from my first result set all rows with flag >= 0 that match the negative flag rows.
These things are always a bit to describe in words, so here is an example with my data set looking something similar to the following:
flag name loc
0 Fred USA
-1 Fred USA
1 Fred CANADA
0 Ryan CANADA
0 Steph SPAIN
-1 Steph SPAIN
1 Steph CANADA
-2 Steph CANADA
2 Steph RUSSIA
If I wanted all data with a flag of 1, I would expect to return the following
flag name loc
1 Fred CANADA
0 Ryan CANADA
1 Steph CANADA
If flag was just 2, I would want
flag name loc
0 Fred USA
0 Ryan CANADA
2 Steph RUSSIA
And finally if flag was 1 OR 2, I would want
flag name loc
1 Fred CANADA
0 Ryan CANADA
2 Steph RUSSIA
Note that although the flag appears to be sequential in this example, it can not be assumed that a higher flagged item is the final flagged row to be chosen. Also, this is a subquery for a larger query that gathers information based on this query. The main query can contain any number of flags.
Is this operation doable in a query, or should I continue doing the heavy lifting in the front-end?
Fiddle: http://sqlfiddle.com/#!18/de297/1
Thanks

This satisfies your first two requirements but I'm not sure what if
if flag was 1 OR 2, I would want
means
DECLARE #YourInt INT = 2
SELECT flag,
name,
loc
INTO #YourInts
FROM table1
WHERE flag = #YourInt
SELECT flag,
name,
loc
FROM #YourInts
UNION ALL
SELECT flag,
name,
loc
FROM table1
WHERE flag = 0 AND
name NOT IN (SELECT name FROM #YourInts WHERE flag = #YourInt)

If I understand correctly, this is prioritization with filtering:
select *
from (select t1.*,
row_number() over (partition by name order by flag desc) as seqnum
from table1 t1
where flag in (0, 1)
) t1
where seqnum = 1;
The where condition has the list of acceptable flag values. It seems you always want 0 in that list.
Here is a db<>fiddle.

Related

SQL subqueries PostgreSQL 12

I'm having a table similar to this:
first
last
date
pos
john
doe
18-03-2021
harris
potter
10-06-2021
john
doe
10-05-2021
harris
potter
14-06-2021
jessica
potter
14-06-2021
kermit
foster
The use case is as follow:
The pos column correspond to a positive covid test
The date column correspond to the vaccination date
To be elligible for a covid certificate, some one must either:
Been tested positive and have got 1 vaccine
Have receive 2 vaccine
I'm trying to write a query that return me:
totalDose, totalRequieredDose
For exemple:
If he has tested positive, the totalRequiredDose is 1 and if he has got 1 vaccine, he is elligible. As such, for Harry Potter, totalDoses=1 and totalRequieredDoses=1 and is elligible
If he has not been tested positive, the totalRequiredDose is 2 and if he has got 2 vaccines, he is elligible. As such, for John Doe, totalDoses=2 and totalRequieredDoses=2 and is elligible
first
last
totalDoses
totalRequieredDoses
john
doe
2
2
harris
potter
1
1
jessica
potter
1
2
kermit
foster
0
2
As Jessica Potter have a vaccine and no pos date, she must have 2 vaccines.
So the value 1/2
And Kermit foster have no pos value, he is 0/2
Etc.
I'm scratching my head to write a query (or pl/sql) that could return me such table.
Could someone give me some hints ?
We can aggregate by first and last name. The total doses is simply the count of non NULL vaccination dates. For the total required number of doses, we can start with a value of 2. This value can then be offset by 1 assuming there exists a non NULL date for the pos column, indicating that a given person tested positive at some point.
SELECT
first,
last,
COUNT(date) AS totalDoses,
2 - (COUNT(*) FILTER (WHERE pos IS NOT NULL) > 0)::int AS totalRequieredDoses
FROM yourTable
GROUP BY
first,
last
ORDER BY
COUNT(date) DESC,
first,
last;
Demo

Return based on values selected

I really don't know how to phrase the title correctly, so please excuse me if the title is confusing.
Here's the scenario I am facing:
I have a table...assuming it contains the follow rows.
Name | Value
----- | ----
John | 1
Mary | 2
Jack | 3
Jim | 4
Here's the PL/SQL requirement:
If John exists, return John and his value.
If John does not exist, but Mary does, return Mary and her value.
If neither John nor Mary exist, return either Jack or Jim whichever
has the higher value.
I was able to use cursor to traverse the table and test each row, but am wondering if there are other more efficient way.
Thanks!
No need for a cursor and a loop. You can do this in a single query, using a conditional sort and a fetch clause:
select *
from mytable
order by
case name when 'John' then 1 when 'Mary' then 2 else 3 end,
value desc
fetch first row only
Or if you are a pre-12c version of Oracle, where the fetch clause is not available:
select name, value
from (
select t.*,
row_number() over(order by
case name when 'John' then 1 when 'Mary' then 2 else 3 end,
value desc
) rn
from mytable t
) t
where rn = 1

Hive sql: count and avg

I'm recently trying to learn Hive and i have a problem with a sql consult.
I have a json file with some information. I want to get the average for each register. Better in example:
country times
USA 1
USA 1
USA 1
ES 1
ES 1
ENG 1
FR 1
then with next consult:
select country, count(*) from data;
I obtain:
country times
USA 3
ES 2
ENG 1
FR 1
then i should get next out:
country avg
USA 0,42 (3/7)
ES 0,28 (2/7)
ENG 0,14 (1/7)
FR 0,14 (1/7)
I don't know how i can obtain this out from the first table.
I tried:
select t1.country, avg(t1.tm),
from (
select country,count(*)as tm from data where not country is null group by country
) t1
group by t1.country;
but my out is wrong.
Thanks for help!! BR.
Divide the each group count by total count to get the result. Use Sub-Query to find the total number of records in your table
Try this
select t1.country, count(*)/IFNULL((select cast(count(*) as float) from data),0)
from data
group by t1.country;

Selecting Properties from Property_Features list

I have two SQL tables:
PROPERTY
PID Address
1 123 Center Road
2 23 North Road
3 3a/34 Crest Avenue
5 49 Large Road
6 2 Kingston Way
7 4/232 Center Road
8 2/19 Ash Grove
9 54 Vintage Street
10 15 Charming Street
PROPERTY_FEATURE
P.PID Feature
1 Wine Cellar
1 Helipad
2 Tennis Court
2 Showroom
7 Swimming Pool - Above Ground
9 Swimming Pool - Below Ground
9 Wine Cellar
I want to Select the properties which contains specific features. For example, I would like to select the property ID which has the features Wine Cellar and Helipad, it would return the Property with the ID of 1.
Any ideas?
You can do this using Group By and Having clause
select PID
From PROPERTY_FEATURE
Group by PID
Having COUNT(case when Feature = 'Wine Cellar' then 1 end) > 0 --1
and COUNT(case when Feature = 'Helipad' then 1 end) > 0 -- 2
1 ) Counts only when Feature = 'Wine Cellar' & > 0 will make sure atleast one 'Wine Cellar' exist for each PID
2) Counts only when Feature = 'Helipad' & > 0 will make sure atleast one 'Helipad' exist for each PID
AND will make sure both 1 & 2 is satisfied then return the PID
You can do this by filtering on the required features, and then grouping and counting in a HAVING clause. You could also group directly (without filtering first) but if the table is very large, with many pid's, that will result in a lot of unnecessary grouping of rows that won't be used in the end.
Something like this:
select pid
from property_feature
where feature in ('Wine Cellar', 'Helipad')
group by pid
having count(feature) = 2;
This assumes there are no duplicates in the table (so you can't have 1 'Helipad' twice, messing up the count). If there can be duplicates, change the last line to count (distinct feature) = 2.

SQL - count without group by? I need to use two ids for a join

I thought I could count a column and add it as a column as I can with a sum but I get an error about having to group by / having. An example of what I want...
Initial table...
Global ID Local ID Name Role
100 1 Andy Manager
100 2 Andy Manager
100 1 John Co-Manager
200 1 Andy Co-Manager
200 2 John Manager
200 2 Mike Manager
I then want to add a column that counts the number of Manager in each group / local pairing...
Global ID Local ID Name Role Manager Count
100 1 Andy Manager 1
100 2 Andy Manager 1
100 1 John Co-Manager 0
200 1 Andy Co-Manager 0
200 2 John Manager 2
200 2 Mike Manager 2
I tried just joining the two tables on the global / local ID and then adding a column for count of the Role. The problem is that I get an error about grouping / having by but I don't want to group anything. I just want to add the column and still have the same number of rows. Any way around this?
FYI - for the last two rows, the last column has 2 because John and Mike are on the same group / local ID
It looks like your definition of a group is a unique combination of [global_id, local_id]. If that is the case you do want to group by those two values, and do a count, where the role is Manager. But because you want other columns from the original table, you must do that count within an inline view, and then join back to the original table, like so:
select t.*, v.mgr_in_grp
from tbl t
left join (select global_id, local_id, count(*) as mgr_in_grp
from tbl
where role = 'Manager'
group by global_id, local_id) v
on t.global_id = v.global_id
and t.local_id = v.local_id
Fiddle: http://sqlfiddle.com/#!2/fb3ace/2/0
Notice that there is a difference on row 3, as compared to your expected output.
John, Co-manager at global_id and local_id 100 and 1, respectively, belongs to a pair that has a manager in that combination (Andy, your first row). So the count appears should be 1.