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.
Related
I'm trying to do a rank (?) across columns where a "Favorites" column is based on the highest value in specified columns.
How the current dataset is:
user
Tops Bought
pants bought
anna
50
12
jon
12
50
& What would like to do is this :
user
Tops Bought
pants bought
favorite item
anna
50
12
tops
jon
12
50
pants
Thank you!
You can use a case expression:
select t.*,
(case greatest(tops_bought, pants_bought)
when tops_bought then 'tops'
when pans_bought then 'pants'
end) as favorite_item
from t;
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.
Let's consider this example :
Clients Routes City Timestamp
1 10 NY 0
1 11 NY 10
1 12 WDC 11
1 13 NY 20
2 22 LA 15
What I want as an output is something like this :
Clients Routes_number City min(Timestamp)
1 2 NY 0
1 1 WDC 11
1 1 NY 20
2 1 LA 15
The idea here is that I have to do multiple group by that kept their orders. For example, if we see the cities for Client 1, we can understand that he travelled from NY -> WDC -> NY (in the same day). So the idea is like to do a group by that counts the routes_number and the minimum timestamp but it will stop EACH TIME it finds a new city. If I do a global group by I will get something like this :
Clients Routes_number City min(Timestamp)
1 3 NY 0
1 1 WDC 11
2 1 LA 15
With an output like this, we lost the information that we have NY-> WDC and AGAIN NY. We thought that he only did NY -> WDC in one way...
I don't even know if it's possible to do such a request using SQL or if I have to do it in my code (I am newbie in Spark & Scala but Scala is the language that I use).
Thank you !
This is a gaps-and-islands problem that can be solved with a difference of row numbers:
select client, city, count(*), min(timestamp)
from (select t.*,
row_number() over (partition by client, city order by timestamp) as seqnum_1,
row_number() over (partition by client order by timestamp) as seqnum_2
from t
) t
group by client, city, (seqnum_2 - seqnum_1);
Here is a db<>fiddle.
It can be tricky to see how the difference of row numbers works to identify adjacent rows with the same city value. If you look at the results of the subquery, you'll get a good idea on how it works.
I have a following dataset that looks like:
ID Medication Dose
1 Aspirin 4
1 Tylenol 7
1 Aspirin 2
1 Ibuprofen 1
2 Aspirin 6
2 Aspirin 2
2 Ibuprofen 6
2 Tylenol 4
3 Tylenol 3
3 Tylenol 7
3 Tylenol 2
I would like to develop a code that would identify patients who have been administered a medication more than once. So for example, ID 1 had Aspirin twice, ID 2 had Aspirin twice and ID 3 had Tylenol three times.
I could be wrong but I think the easiest way to do this would be to concatenate each ID based on Medication using a code similar to the one below; but I'm not quite sure what to do after that - is it possible to count if a string appears twice within a cell?
SELECT DISTINCT ST2.[ID],
SUBSTRING(
(
SELECT ','+ST1.Medication AS [text()]
FROM ED_NOTES_MASTER ST1
WHERE ST1.[ID] = ST2.[ID]
Order BY [ID]
FOR XML PATH ('')
), 1, 200000) [Result]
FROM ED_NOTES_MASTER ST2
I would like the output to look like the following:
ID MEDICATION Aspirin2x Tylenol2x Ibuprofen2x
1 Aspirin, Tylenol , Aspirin YES NO NO
2 Ibuprofen, Aspirin, Aspirin YES NO NO
3 Tylenol, Tylenol ,Tylenol NO YES NO
For the first part of your question (identify patients that have had a particular medication more than once), you can do this using GROUP BY to group by the ID and medication, and then using COUNT to get how many times each medication was given to each patient. For example:
SELECT ID, Medication, COUNT(*) AS amount
FROM ST2
GROUP BY ID, Medication
This will give you a list of all ID - Medication combinations that appear in the table and a count of how many times each combo appears. To limit these results down to just those that are greater than 2, you can add a condition to the COUNTed field using HAVING:
SELECT ID, Medication, COUNT(*) AS amount
FROM ST2
GROUP BY ID, Medication
HAVING amount >= 2
The problem now is formatting the results in the way you want. What you will get from the query above is a list of all patient - medication combinations that came up in the table more than once, like this:
ID | Medication | Count
------+---------------+-------
1 | Aspirin | 2
2 | Aspirin | 2
3 | Tylenol | 3
I'd suggest that you try and work with this format if possible, because as you have found, to get multiple values returned in a comma delimited list as you have in your Medication column you have to resort to some hacks to get it to work (although a recent version of SQL Server does implement some sort of proper group concatenation functionality.). If you really need the Aspirin2x etc. columns, take a look at the PIVOT operation in SQL Server.
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.