Oracle SQL: How to write below SQL in Oracle - sql

There is a table t1:
id type
1 a
1 b
2 c
2 a
3 a
3 a
4 a
Now I need to check if the id only has type a and the count is 1 (single), i.e., only id 4 satisfies this condition in the data above
SELECT type, COUNT (1)
FROM t1
where id = :id
GROUP BY type
HAVING COUNT (1) = 1;
I use the above SQL query to get the data and then use it in code. It's not a good solution, can anyone help me to get the correct result with one SQL query?

I'd group by the ID and filter on two counts:
Total count is 1
Count of rows that aren't type a (using a case statement) is 0
SELECT id
FROM t1
GROUP BY id
HAVING COUNT(*) = 1 AND COUNT(CASE WHEN type <> 'a' THEN 1 END) = 0

You want a simple aggredated query with a HAVING BY clause that ensures that only one row exists and that its type is equal to 'a'.
SELECT id
FROM t1
GROUP BY id
HAVING COUNT(*) = 1 and SUM(DECODE(type, 'a', 0, 1)) = 0

I would simply do:
SELECT id
FROM t1
GROUP BY id
HAVING COUNT(*) = 1 AND MIN(type) = 'a';

You need id in group by clause & just filter out the types with having clause :
SELECT id
FROM t1
GROUP BY id
HAVING MIN(type) = MAX(type) AND MIN(type) = 'a';

Related

Removing rows from result set where column only has one value against a user

I have a result set
name stage value
---- ----- -----
jim 1 4
jim 1 8
paul 1 8
paul 1 8
want to remove the rows where 8 is the only value against a person
keep the 2 jim rows and lose the 2 paul rows
You can use not exists. For a select query:
select t.*
from t
where not exists (select 1
from t t2
where t2.name = t.name and t2.value = 8
);
Similar logic (except using exists rather than not exists) can be used for a delete -- if you really want to delete the rows from the table.
If you have a complex query that you don't want to repeat, then window functions are helpful:
select t.*
from (select t.*,
sum(case when value = 8 then 1 else 0 end) over (partition by name) as cnt_8
from t
) t
where cnt_8 = 0;
If your database support analytical function then you can use count as follows:
Select * from
(Select t.*,
Count(case when value <> 8 then 1 end) over (partition by name) as cnt
From your_table t) t
Where cnt > 0
Assuming you also have an ID column (defined as an auto increment integer) defined in your table this query would select the row with the highest id for each unique combination:
select max(id) from t group by name,stage,value
In your example this would only return the latest id for rows having values paul,1,8 in columns name,stage,value respectively.
You can then use the prior query to filter out any duplciates using it in the where clause:
select * from t
where id in (select max(id) from t group by name,stage,value)
Finally you can also delete rows that are not unique if that's your goal:
delete from t
where not id in (select max(id) from t group by name,stage,value)

SQL query to return rows where only one record is present in a given status

I have a table with data similar to below. I am trying to get a list of results that will display all rows where only one unique SourceID exists in status 10. If I were querying this table, I would expect ID's 3 and 4 to be returned.
Table Example
Select *
From table
Where Status = 10 and Source ID in
(
Select SourceID
From Table
Group by SourceID
Having Count(*) = 1
)
You can use NOT EXISTS :
SELECT t.*
FROM table t
WHERE NOT EXISTS (SELECT 1 FROM table t1 WHERE t1.SourceID = t.SourceID AND t1.Status <> t.Status);
Maybe that would work?
SELECT ID FROM Mytable
WHERE [Status] = 10
GROUP BY ID
HAVING COUNT(SourceID) = 1
First, find out all the unique SourceIDs
SELECT
SourceID
FROM
Data
GROUP BY
SourceID
HAVING
COUNT(SourceID) = 1
And then use this query as a sub query to get all the rows that has unique SourceID;
SELECT
*
FROM
Data
WHERE
SourceID IN (
SELECT
SourceID
FROM
Data
GROUP BY
SourceID
HAVING
COUNT(SourceID) = 1
)
Use a sub-query to check if t there is an exact count of 1 of those source id's
SELECT t.* FROM YourTable t WHERE t.status = 10
AND
(SELECT COUNT(0) x From YourTable t2
where t2.sourceid = t.sourceid) = 1

Sql Server - Return all records after the last instance of a trigger value

In the below example, the query needs to return all records after, and including, the last 'bar' (sorted by Id). So it would return the last three records.
If 'bar' doesn't exist, the query needs to return all records.
Id Trigger
1 foo
2 foo
3 **bar**
4 foo
5 **bar**
6 foo
7 foo
Trying to figure out an elegant solutions without (or minimal) subqueries, if-thens, variables...
You can use a subquery to compute the maximum id of rows that contain 'bar'. When the subquery returns no rows, COLAESCE can be used to provide a default value of 0.
SELECT t.id
FROM mytable t
WHERE t.id >= COALESCE(
(SELECT max(id) from mytable where trigger = 'bar'),
0
)
db<>fiddle here
WITH mytable as (
SELECT 1 id, 'a' trig
UNION ALL SELECT 2, 'foo'
UNION ALL SELECT 3, 'bar'
UNION ALL SELECT 4, 'zoo'
)
SELECT id
FROM mytable t
WHERE id >= COALESCE(
(SELECT max(id) from mytable where trig = 'bar'),
0
)
GO
| id |
| -: |
| 3 |
| 4 |
You can use a correlated subquery that uses conditional aggregation to get the maximum ID where the value is equal to 'bar' or the minimum ID if there was no 'bar'.
SELECT *
FROM [elbat] t1
WHERE t1.[id] >= (SELECT coalesce(max(CASE t2.[trigger]
WHEN 'bar' THEN
t2.[id]
END),
min(t2.[id]))
FROM [elbat] t2);
db<>fiddle
Basically, you want all rows where there is not a row with a greater 'bar' value. I think the most elegant way to express this is:
select t.*
from t
where not exists (select 1
from t t2
where t2.trigger = 'bar' and t2.id > t.id
);
Another method uses window functions:
select t.*
from (select t.*,
max(case when trigger = 'bar' then id end) over () as max_bar_id
from t
)
where max_bar_id is null or
id >= max_bar_id;
Another one using Windowed Aggregates, mainly usefull if the base data is the result of complex query (because there's only one access to it) or you need to assign multiple foo/bar groups:
WITH cte AS
(
SELECT *
-- cumulative count, assigns 0 to the first group of foo/bar rows
,Count(CASE WHEN [trigger] = 'bar' THEN 1 end) -- only count 'bar'
Over (ORDER BY id DESC -- highest id first
ROWS BETWEEN Unbounded Preceding AND 1 Preceding) AS flag
FROM tab
)
SELECT *
FROM cte
WHERE flag = 0 -- first group
See db<>fiddle

how do I make multiple count under having clause

some sample data:
Id name value ref
1 ab xy
2 aba z
3 ab xy
4 abc def
5 gxr mdy
what I am trying to do is to get the two column that appeared more than once
so row 1 and row 3 would be selected.
select name, value from table_x
where value is not null group by name having count(name) >= 2
and having count(value) >= 2;
got stucked.....
#vkp's answer is correct if you only care about finding the distinct name/value pairs that appear more than once. But if you actually want the individual rows that satisfy the criteria, try this:
SELECT t1.Name, t1.[Value]
FROM Table_X t1
JOIN
(
SELECT Name, [Value]
FROM Table_X
where [Value] IS NOT NULL
GROUP BY Name, [Value]
HAVING COUNT(1) >= 2
) t2 ON t1.Name = t2.Name AND t1.[Value] = t2.[Value]
Your syntax is incorrect. group by name and value and check for count >=2 thereafter.
select name, value
from table_x
where value is not null
group by name, value
having count(*) >= 2;

Find out particular id

I have a table in sql like this:
id billpay
-------------------------
1024 0
1024 0
1024 1
1025 1
1025 1
I want to retrieve only those id having billpay 1
Please help me with this
Try this:
select distinct id from yourtable where billpay = 1
It should be like this:
SELECT id FROM tabel WHERE billpay = 1;
This will retrieve those ids in ascending order which have at least one record in the table with billpay = 1.
The DISTINCT keyword will ensure you don't receive back multiple records with the same id.
SELECT DISTINCT id
FROM [TableName]
WHERE billpay = 1
ORDER BY id ASC
If you want to exclude those ids which also have records with billpay = 0, then use this:
SELECT DISTINCT id
FROM [TableName]
WHERE billpay = 1
AND id NOT IN (SELECT id FROM [TableName] WHERE billpay = 0)
ORDER BY id ASC
Regards,
select ID
from MyData
Where billpay = 1
Group By ID
The group by will list unique IDs
select ID
from MyData A
Where not exists (select 'X' from MyData B where B.billpay <> 1 and B.ID = A.ID)
Group By ID
This will only list IDs where billpay is only 1
Try this:
SELECT id
FROM mytable
GROUP BY id
HAVING COUNT(CASE WHEN COALESCE(billpay, 0) <> 1 THEN 1 END) = 0
The above will select only those ids associated to billpay=1 and nothing but billpay=1.
SQL Fiddle Demo
The following query selects the ids from group of ids where the number of records with billpay = 1 is the same as the number of records in the group
select id
from bills
group by id
having sum(billpay) = count(id)
Use NOT EXISTS to find rows with no other than billplay 1, use DISTINCT to return only one of each id found.
select distinct id
from tablename t1
where not exists (select 1 from tablename t2
where t1.id = t2.id
and t2.billpay <> 1)
Try to use GROUP BY +MIN statement to exclude Id's with existing billpay=0
SELECT id
FROM yourtable
GROUP BY id
HAVING MIN(billpay)=1