Selecting Data from Same Table that Doesn't Match - sql

I have found several solutions for my type of problem, but I having trouble applying it in my situation.
Essentially I have a Vehicle Table:
License VIN Region
1 1 1
1 2 2
2 3 1
2 3 2
3 4 1
3 4 2
3 5 3
I want to take the license and vin from region 1 and see if the vin matches in all other regions based on the license. If it doesn't I want all the rows that don't match, but if it does match I don't want the row. So a complexity does come in when say I have 3 licenses and region 1 matches one row, but not the other, I want both the unmatched and region 1; however, when I have 3 licenses that all match I don't want any rows including region 1.
So my results in this case would be:
License VIN Region
1 1 1
1 2 2
3 4 1
3 5 3
I am using SQL Server 2005.

I think this is what you're looking for
SELECT DISTINCT a.*
FROM Vehicle AS a
INNER JOIN Vehicle AS b
ON a.License = b.License
WHERE a.VIN != b.VIN
AND a.Region != b.Region
AND (a.Region = 1 OR b.Region = 1)

Related

SQL Query left join not filtering data

This is my query
SELECT
tblDiseases.disease
FROM
tblRel
LEFT JOIN
tblDiseases ON tblRel.diseaseID = tblDiseases.diseaseID
WHERE
tblRel.symptomID = '1' AND tblRel.symptomID = '2' AND tblRel.symptomID = '3'
and here are my tables
#tblDiseases - holds all disease names
######################################
diseaseID | disease
-----------------------
1 Tifoyd
2 Jondis
3 Malarya
4 Pneomonia
5 Dengu
#tblSymptoms - holds all symptoms
#################################
symptomID | symptom
-------------------------
1 Headache
2 Temparature
3 Less Pain
4 Sever Pain
5 Mussle Pain
#tblRel - holds relation between diseases and symptoms
######################################################
relID | dieaseID | symptomID
-----------------------------
1 1 1
2 1 2
3 3 1
4 3 2
5 3 3
I have selected the disease with symptoms "headache" "temperature" and "less pain" so it should give "Malarya" but instead it gives nothing.
A single column in a single row cannot have three different values. What you want is aggregation, to compare values in different rows:
SELECT d.disease
FROM tblRel r JOIN
tblDiseases d
ON r.diseaseID = d.diseaseID
WHERE r.symptomID IN (1, 2, 3)
GROUP BY d.disease
HAVING COUNT(*) = 3; -- has all three symptoms
Note that LEFT JOIN is not necessary, because you need a match to name the disease. (Presumably, the disease ids match between the tables, as they would in a well-formed database.)

Best way to by column and aggregation on another column

I want to create a rank column using existing rank and binary columns. Suppose for example a table with ID, RISK, CONTACT, DATE. The existing rank is RISK, say 1,2,3,NULL, with 3 being the highest. The binary-valued is CONTACT with 0,1 or FAILURE/SUCESS. I want to create a new RANK that will order by RISK once a certain number of successful contacts has been exceeded.
For example, suppose the constraint is a minimum of 2 successful contacts. Then the rank should be created as follows in the two instances below:
Instance 1. Three ID, all have a min of two successful contacts. In that case the rank mirrors the risk:
ID risk contact date rank
1 3 S 1 3
1 3 S 2 3
1 3 F 3 3
1 3 F 4 3
2 2 S 1 2
2 2 S 2 2
2 2 F 3 2
2 2 F 4 2
3 1 S 1 1
3 1 S 2 1
3 1 S 3 1
Instance 2. Suppose ID=1 has only one successful contact. In that case it is relegated to the lowest rank, rank=1, while ID=2 gets the highest value, rank=3, and ID=3 maps to rank=2 because it satisfies the constraint but has a lower risk value than ID=2:
ID risk contact date rank
1 3 S 1 1
1 3 F 2 1
1 3 F 3 1
1 3 F 4 1
2 2 S 1 3
2 2 S 2 3
2 2 F 3 3
2 2 F 4 3
3 1 S 1 2
3 1 S 2 2
3 1 S 3 2
This is SQL, specifically Hive. Thanks in advance.
Edit - I think Gordon Linoff's code does it correctly. In the end, I used three interim tables. The code looks like that:
First,
--numerize risk, contact
select A.* ,
case when A.risk = 'H' then 3
when A.risk = 'M' then 2
when A.risk = 'L' then 1
when A.risk is NULL then NULL
when A.risk = 'NULL' then NULL
else -999 end as RISK_RANK,
case when A.contact = 'Successful' then 1
else NULL end as success
Second,
-- sum_successes_by_risk
select A.* ,
B.sum_successes_by_risk
from T as A
inner join
(select A.person, A.program, A.risk, sum(a.success) as sum_successes_by_risk
from T as A
group by A.person, A.program, A.risk
) as B
on A.program = B.program
and A.person = B.person
and A.risk = B.risk
Third,
--Create table that contains only max risk category
select A.* ,
B.max_risk_rank
from T as A
inner join
(select A.person, max(A.risk_rank) as max_risk_rank
from T as A
group by A.person
) as B
on A.person = B.person
and A.risk_rank = B.max_risk_rank
This is hard to follow, but I think you just want window functions:
select t.*,
(case when sum(case when contact = 'S' then 1 else 0 end) over (partition by id) >= 2
then risk
else 1
end) as new_risk
from t;

SQL Server : how can I get difference between counts of total rows and those with only data

I have a table with data as shown below (the table is built every day with current date, but I left off that field for ease of reading).
This table keeps track of people and the doors they enter on a daily basis.
Table entrance_t:
id entrance entered
------------------------
1 a 0
1 b 0
1 c 0
1 d 0
2 a 1
2 b 0
2 c 0
2 d 0
3 a 0
3 b 1
3 c 1
3 d 1
My goal is to report on people and count entrances not used(grouping on people), but ONLY if they entered(entered=1).
So using the above table, I would like the results of query to be...
id count
----------
2 3
3 1
(id=2 did not use 3 of the entrances and id=3 did not use 1)
I tried queries(some with inner joins on two instances of same table) and I can get the entrances not used, but it's always for everybody. Like this...
id count
----------
1 4
2 3
3 1
How do I not display results id=1 since they did not enter at all?
Thank you,
You could use conditional aggregation:
SELECT id, count(CASE WHEN entered = 0 THEN 1 END) AS cnt
FROM entrance_t
GROUP BY id
HAVING count(CASE WHEN entered = 1 THEN 1 END) > 0;
DBFiddle Demo

Matching two variables to create a new ID

I'm trying to create an SQL statement to match either an id number or a postcode and then assign a new id number
What I want to end up with is ‘newid’ that correctly recognizes that the first four records are the same person (even though the postcode for record 2 is different).
record id postcode newid
--------------------------
1 1 1 1
2 1 2 1
3 1 1 1
4 2 1 1
5 3 3 2
Any suggestions would be appreciated greatly.
Going based on your example:
SELECT RECORD,
(SELECT MIN (ID)
FROM users u2
WHERE users.id IN (u2.id, u2.postcode)
OR users.postcode in (u2.id, u2.postcode)
) AS newid
FROM users
This results with the following data:
RECORD NEWID
------------------
1 1
2 1
3 1
4 1
5 3
Here is the SQLFiddle

Grouping a row based on field in a different table in oracle

I am working with these two tables for the past two days
parts_list table:
PART_ID VENDOR_ID LABEL
1 5 A
1 2 B
1 3 C
2 2 D
2 3 E
3 3 F
vendor_prsdnc table:
VENDOR_ID PRSCDNC
5 3
2 2
3 1
Can anybody please tell me how to retrieve the label of each part from the vendor with highest precedence? For example the part with id one is supplied by 3 vendors but we need the one from vendor with highest precedence ie 5. The expected result is:
PART_ID VENDOR_ID LABEL
1 5 A
2 2 D
3 3 F
[Vendor Id is not proportional with the precedence ]
I have this query
SELECT
SDS.PART_ID,
SDSIS.VENDOR_ID,
MAX(SDSIS.PRSCDNC)
FROM PARTS_LIST SDS,VENDOR_PRSDNC SDSIS
WHERE SDS.VENDOR_ID=SDSIS.VENDOR_ID
GROUP BY SDS.PART_ID,SDSIS.VENDOR_ID;
but it does not return the expected result.
Not tested ,but it should work i think
select part_id,vendor_id,label
from
(
select pl.part_id
,pl.vendor_id
,pl.label
,vp.prscdnc
,max(vp.prscdnc) over (partition by pl.part_id) mx
from part_list pl,vendor_prsdnc vp
where pl.vendor_id=vp.vendor_id
)
where prscdnc =mx;