Select Condition Based on Multiple rows - sql

I have a Table Like this:
TableA
----------------------------
ID - Name - PatID
1 A 10
2 B 10
3 A 11
4 A 12
5 B 13
I want to select All Such PatID Which has Name=A and Name = B.
So i should only get 10 as result.
What should be query for this?

You should be able to use the following query to get the result:
select patid
from tablea
where name in ('A', 'B')
group by patid
having count(distinct name) = 2;
See SQL Fiddle with Demo

If you need information from the A group and the B group you could also do it like this:
SELECT AGroup.ID AS AId, BGroup.ID AS BId
FROM TableA AGroup
JOIN TableB BGroup
ON AGroup.Name = 'A'
AND BGroup.Name = 'B'
AND AGroup.PatID = BGroup.PatID
This also retains duplicates if you have more than one entry, for Name = A and PatID = 10 for example.

Related

sql multiple filter all conditions in a group

I have a table with 3 fields:
id order date
1 1 null
1 2 not null
1 3 null
2 1 null
2 2 null
2 3 null
2 4 not null
3 1 null
I need the "id" in which:
ALL the "order" in (1,2,3)
and
ALL the "date" is null (so it is id 2)
I've tried as follows:
where order in (1,2,3) and date is null
but it returns both id 2 and id 1 (I'm expecting id 2 only).
Thanks for helps.
ID 3 should be also included. It satisfies your condition.
SELECT distinct id
FROM tab1 aa
WHERE aa.order IN (1, 2, 3) AND aa.data IS NULL
AND NOT exists(SELECT 1
FROM tab1 bb
WHERE ((bb.order IN (1, 2, 3) AND bb.data IS NOT NULL)
OR
(bb.order NOT IN (1, 2, 3) AND bb.data IS NULL))
AND aa.id = bb.id);
If you don't want ID 2 cause it has order in ID 4, then relax the last condition in:
bb.order NOT IN (1, 2, 3)
without the check in the date.
If with
ALL the "order" in (1,2,3)
you mean that there should be an order for 1, an order for 2 and an order for 3, then you should add and exists in the query to check this, like
and exists (select 1 form tab1 cc where aa.id = cc.id and cc.order = 1 and cc.data is not null)
and so on.
You want a result per ID, so GROUP BY it. You are only interested in order 1, 2, and 3, so use a WHERE clause. You only want IDs with all three orders and no date set. You can check this after aggregation in the HAVING clause.
select id
from mytable
where "order" in (1,2,3)
group by id
having count(*) = 3 -- all three IDs
and count("date") = 0; -- no non-null date
Rextester demo: http://rextester.com/SEE91944
(I surmise the table's unique key is id + order. Otherwise you'd have to COUNT(DISTINCT "order") and maybe to check null dates differently. As both order and date are SQL words, I am using quotes on them. You should avoid such names.)
I'm not sure what database are you using so I tried to right a query that should work with most. Have a look:
select * from
(select
id,
SUM(case
when [order] = 1 and [date] is null then 1
when [order] = 2 and [date] is null then 1
when [order] = 3 and [date] is null then 1
else 0
end) score
from test
group by id) scores
where score = 3
http://sqlfiddle.com/#!18/e4334/9
Sorry but none of above solved my question.
I solved it using "where not exists" (excluding the unwanted)
thanks to you all for your efforts.
If I've correctly interpreted your question, the following SQL does the work.
It returns id values of records for which all order who have 1, 2 or 3 value have null value for the date field:
SELECT DISTINCT id
FROM t
WHERE
order IN (1, 2, 3) AND
date IS NULL AND
id NOT IN (
SELECT id
FROM t
WHERE
order IN (1, 2, 3) AND
date IS NOT NULL
)

SQL-Get highest record from group at another table

I have read several answers to related questions but none of them can be applied to this case.
I have a table TableA where several groups are listed, with their score:
GROUP|SCORE
Blue | 0
Green| 0
Red | 0
Orange| 0
On another table TableB, I have the parts of each group and their individual score (status), which can have three different values:
- G (Good)
- A (Average)
- B (Bad)
So tableB is:
GROUP|PART|STATUS
Blue | 3H2| A
Blue | 4NQ| G
Blue | W9X| A
Green| 65D| G
Red | 73F| B
Red | 91G| A
I need to Update the score on TableA in the following way:
If the best status between the parts of the group is G, group score is 3
If the best status between the parts of the group is A, group score is 2
If the best status between the parts of the group is B, group score is 1
I have been a couple of days going around this and I can't find a solution. Thank you guys. Btw, I am using Access 2013.
As I have already mentioned in the comments: Don't store the score redundantly; it is implicit in tableB. And to get your database straight introduce a status table:
STATUS DESCRIPTION SCORE
G Good 3
A Avarage 2
B Bad 1
If you want to select the score for each color group use this query for instance:
select b.colorgroup, max(s.score) as maxscore
from tableb as b
join status as s on s.status = b.status
group by b.colorgroup;
Two alternative ways to write the same query:
select
colorgroup,
(
select max(score)
from status as s
where s.status = b.status
) as maxscore
from tableb as b;
and
select b.colorgroup, s.maxscore
from tableb as b
join
(
select status, max(score) as maxscore
from status
group by status
) as s on s.status = b.status;
(BTW: I called your group colorgroup because GROUP is a reserved name in SQL.)
UPDATE You say you cannot add a table to the database. So you must evaluate the score in the query itself unfortunately. In standard SQL you would use CASE WHEN, which MS Access doesn't feature. MS Access provides IIF instead:
select
colorgroup,
max(iif(status = 'G', 3, iif(status = 'A', 2, 1))) as maxscore
from tableb
group by colorgroup;
If you even must use the column in tableA and store redundantly, use:
update tablea as a
set score =
(
select
max(iif(status = 'G', 3, iif(status = 'A', 2, 1))) as maxscore
from tableb as b
where b.colorgroup = a.colorgroup
);
In SQL-Server you could do in following:
QUERY
update a
set a.SCORE = MaxSTATUS
from #a a
join (select GROUP_, MAX(case when b.STATUS_ = 'G' then 3
when b.STATUS_ = 'A' then 2
when b.STATUS_ = 'B' then 1
end) MaxSTATUS
from #b b
group by GROUP_
) b ON a.GROUP_ = b.GROUP_
select * from #a
SAMPLE DATA
CREATE TABLE #a
(
GROUP_ NVARCHAR(60),
SCORE INT
)
INSERT INTO #a VALUES
('Blue',0)
,('Green',0)
,('Red',0)
,('Orange',0)
CREATE TABLE #b
(
GROUP_ NVARCHAR(60),
PART NVARCHAR(60),
STATUS_ NVARCHAR(60),
)
INSERT INTO #b VALUES
('Blue','3H2','A')
,('Blue','4NQ','G')
,('Blue','W9X','A')
,('Green','65D','G')
,('Red','73F','B')
,('Red','91G','A')
OUPUT
GROUP_ SCORE
Blue 3
Green 3
Red 2
Orange 0

How to GROUP multiple records from two different SQL statements

I have a table called tbl which contains all the data I need. I have many columns in this table, but for purposes of this example I will only list the columns necessary to accomplish this task.
Here's how data stored in the tbl (note uID is char(20) and cID is int)*:
uID cID
1 10
1 11
1 12
2 11
We usually query this table like
SELECT * FROM tbl WHERE uID = "1"
So it returns
uID cID
1 10
1 11
1 12
But I also need to return the row where uID is different but cID do match. Or grab the uID of the second row (which is 2) based on cID and do a select statement like this:
SELECT * FROM tbl WHERE uID in ('1','2')
That query will return what I'm looking for
uID cID
1 10
1 11
1 12
2 11
This table contains a lot of rows and I want to be able to do this programatically for every call where cID matches and uID is different.
Any suggestions?
I think this may be what you want:
SELECT *
FROM tbl
WHERE uID = '1'
UNION ALL
SELECT *
FROM tbl
WHERE uID <> '1' AND
EXISTS (select 1 from tbl tbl2 where tbl2.uId = '1' and tbl2.cID = tbl.cID);
or something like this:
SELECT uID, cID
FROM tbl
WHERE uID IN
(
SELECT uID
FROM tbl
INNER JOIN
(
SELECT cID
FROM tbl
GROUP BY cID
HAVING count(*) > 1
) c ON c.cID = tbl.cID
)

Select from a table based on another table Number of records Oracle

I have a unique requirement to select records from one table based on another table only if the second table has at least one record with a certain flag. The query should not return two records for the same ID: example:
Table 1
id name location
4 myname MyLocation
6 hisname HisLocation
7 hername herlocation
The id in this table are unique:
Table two
id details1 details2 closureflg
4 somdetails somedetails Y
4 somdetails somedetails Y
6 somdetails somedetails N
7 somdetails somedetails N
7 somdetails somedetail N
I need to select from the first table one record only as long as the corresponding id has records in Table 2 whose closure flag is N:
I have tried:
select * from table1 where id in(select id from tbale2 where closureflg = 'N');
this returns two records for id 7;
My expected output:
id name location
6 hisname HisLocation
7 hername herlocation.
Please help.
please, try this one
SELECT *
FROM table1 t1
WHERE EXISTS(SELECT * FROM table2 t2 WHERE closureflag = 'N' AND t1.ID = t2.ID);
I would try it with a join
select id, name, location from table1
join table2 on table1.id=table2.id
where table2.closureflg = 'N'
group by id

Custom order in SQL

We are querying database to retrieve data in following fashion
select a,b,...f from table1 where id in (6,33,1,78,2)
The result I got from query is in following order 1,2,6,33,78.
I want the result in same order (6,33,1,78,2). Is there any way to retrieve the data in same order.
EDIT
*I am using SQL 2008*
add this order by clause
order by case
when id = 6 then 1
when id = 33 then 2
when id = 1 then 3
when id = 78 then 4
when id = 2 then 5
end
If using MySQL you can do this
ORDER BY FIND_IN_SET(id, '6,33,1,78,2')
Using a Table Value Constructor:
SELECT a, b, ... f
FROM
table1
JOIN
( VALUES
(1, 6),
(2, 33),
(3, 1),
(4, 78),
(5, 2)
) AS ordering (position, id)
ON ordering.id = table1.id
ORDER BY position
I don't know the background, but usually I achieve this custom order in an additional orderIndex column. This way I can manually manage the order when inserting to the table and add this column to the ORDER BY clause of the default queries
If you use SQL Server you could use charindex.
select A, B
from Table1
where ID in (6,33,1,78,2)
order by charindex(','+cast(ID as varchar(10))+',', ',6,33,1,78,2,')
ugly solution:
select a,b,...f from table1 where id in 6
UNION
select a,b,...f from table1 where id in 33
and so on..
"better" solution:
add another column on your query and do case 6 then 0, case 33 then 1 and so on
select a,b,...f , case id when 6 then 0 when 33 then 1 <and so on> end
from table1 where ...
and then order by this new column