how to select set of records is ID is present in one of them - sql

Here is the table where ORGID/USERID makes unique combination:
ORGID USERID
1 1
1 2
1 3
1 4
2 1
2 5
2 6
2 7
3 9
3 10
3 11
I need to select all records (organizations and users) wherever USERID 1 is present. So USERID=1 is present in ORGID 1 and 2 so then select all users for these organizations including user 1 itself, i.e.
ORGID USERID
1 1
1 2
1 3
1 4
2 1
2 5
2 6
2 7
Is it possible to do it with one SQL query rather than SELECT *.. WHERE USERID IN (SELECT...

You could use exists:
select *
from mytable t
where exists (select 1 from mytable t1 where t1.orgid = t.orgid and t1.userid = 1)
Another option is window functions. In Postgres:
select *
from (
select t.*,
bool_or(userid = 1) over(partition by orgid) has_user_1
from mytable t
) t
where has_user_1
Or a more generic approach, that uses portable expressions:
select *
from (
select t.*,
max(case when userid = 1 then 1 else 0 end) over(partition by orgid) has_user_1
from mytable t
) t
where has_user_1 = 1

Yes, you can do it with a single select statement - no in or exists conditions, no analytic or aggregate functions in a subquery, etc. Why you want to do it that way is not clear; in any case, it is possible that the solution below is also more efficient than the alternatives. You will have to test on your real-life data to see if that is true.
The solution below has two potential disadvantages: it only works in Oracle (it uses a proprietary extension of SQL, the match_recognize clause); and it only works in Oracle 12.1 or higher.
with
my_table(orgid, userid) as (
select 1, 1 from dual union all
select 1, 2 from dual union all
select 1, 3 from dual union all
select 1, 4 from dual union all
select 2, 1 from dual union all
select 2, 5 from dual union all
select 2, 6 from dual union all
select 2, 7 from dual union all
select 3, 9 from dual union all
select 3, 10 from dual union all
select 3, 11 from dual
)
-- End of SIMULATED data (for testing), not part of the solution.
-- In real life you don't need the WITH clause; reference your actual table.
select *
from my_table
match_recognize(
partition by orgid
all rows per match
pattern (x* a x*)
define a as userid = 1
);
Output:
ORGID USERID
---------- ----------
1 1
1 2
1 3
1 4
2 1
2 5
2 7
2 6

You can use exists:
select ou.*
from orguser ou
where exists (select 1
from orguser ou ou2
where ou2.orgid = ou.orgid and ou2.userid = 1
);

Apart from Exists and windows function, you can use IN as follows:
select *
from your_table t
where t.orgid in (select t1.orgid from your_table t1 where t1.userid = 1)

Related

Oracle - generate a running number by group

I need to generate a running number / group sequence inside a select statement for a group of data.
For example
Group Name Sequence
1 a 1
1 b 2
1 c 3
2 d 1
2 e 2
2 f 3
So for each group the sequence should be a running number starting with 1 depending on the order of column"Name".
I already pleayed around with Row_Number() and Level but I couldn't get a solution.
Any idea how to do it?
Analytic functions help.
SQL> with test (cgroup, name) as
2 (select 1, 'a' from dual union all
3 select 1, 'b' from dual union all
4 select 1, 'c' from dual union all
5 select 2, 'd' from dual union all
6 select 2, 'e' from dual union all
7 select 2, 'f' from dual
8 )
9 select cgroup,
10 name,
11 row_number() over (partition by cgroup order by name) sequence
12 from test
13 order by cgroup, name;
CGROUP N SEQUENCE
---------- - ----------
1 a 1
1 b 2
1 c 3
2 d 1
2 e 2
2 f 3
6 rows selected.
SQL>
Try this
SELECT
"Group",
Name,
DENSE_RANK() OVER (PARTITION BY "Group" ORDER BY Name) AS Sequence
FROM table;

Always show a value highst when sorting

I Oracle, I have a table with following values
1
2
4
10
I always want 2 to show up highest following by all other values in DESCending order, as follows :
2
10
4
1
You can order by a value you build with a case; for example:
with tab(col) as (
select 1 from dual union all
select 2 from dual union all
select 4 from dual union all
select 10 from dual
)
select col
from tab
order by case when col = 2 then 1 else 2 end asc,
col desc
gives:
COL
----------
2
10
4
1
try like below if column is not null
with tab(col) as (
select 1 from dual union all
select 2 from dual union all
select 4 from dual union all
select 10 from dual
)
select col
from tab
ORDER BY NULLIF(col, 2) desc NULLS FIRST
output
COL
2
10
4
1
demo link

Cannot figure out logic to update a table

I have below table.
TABLE: ABCD
B column have value 1 whenever there is a change in A column. Now I have to update the table like below. How can I do that?
You can do this using a correlated subquery:
update t
set b = (select sum(t2.b) from t t2 where t2.A <= t.A);
This is standard SQL and should work in either Oracle or Teradata.
Lets have a slightly more complicated example (where the changes in B are not correlated to the changes in A):
Oracle Setup:
CREATE TABLE ABCD( A, B ) AS
SELECT 1, 0 FROM DUAL UNION ALL
SELECT 1, 0 FROM DUAL UNION ALL
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 2, 0 FROM DUAL UNION ALL
SELECT 3, 0 FROM DUAL UNION ALL
SELECT 3, 1 FROM DUAL UNION ALL
SELECT 3, 0 FROM DUAL;
Update:
UPDATE ABCD t1
SET b = (
SELECT sm
FROM (
SELECT ROWID AS id,
SUM( b ) OVER ( ORDER BY a, ROWNUM ) AS sm
FROM ABCD
) t2
WHERE t1.ROWID = t2.ID
);
Output:
SELECT * FROM ABCD;
A B
- -
1 0
1 0
1 1
2 2
2 2
3 2
3 3
3 3
(Note: This is an Oracle solution; I have no idea if it will or won't work in Teradata.)

Oracle logic to roll the value same level

I am facing issue is solving on oracle logic
I have below requirement, I have one table with Some Numbers and Corresponding ID. I want to write logic where few rows are rolled same No. Please let me know what is best way to solve this. I have used left outer join on same table but its giving me cross join.
NO ID
1 A
1 B
1 C
2 A
2 B
2 C
NO ID RoID
1 A C
1 B
2 A C
2 B
You could achieve your desired output using Analytic functions:
MAX() OVER()
LAG() OVER()
For example,
SQL> WITH sample_data AS(
2 SELECT 1 NO, 'A' ID FROM dual UNION ALL
3 SELECT 1 NO, 'B' ID FROM dual UNION ALL
4 SELECT 1 NO, 'C' ID FROM dual UNION ALL
5 SELECT 2 NO, 'A' ID FROM dual UNION ALL
6 SELECT 2 NO, 'B' ID FROM dual UNION ALL
7 SELECT 2 NO, 'C' ID FROM dual
8 )
9 -- end of sample_data mocking a real table
10 SELECT no,
11 id,
12 lag(rn) over(PARTITION BY NO ORDER BY ID DESC) rn
13 FROM
14 ( SELECT t.*, MAX(ID) OVER(PARTITION BY NO ORDER BY ID DESC) rn FROM sample_data t
15 )
16 WHERE ID <> rn
17 ORDER BY no,
18 id;
NO I R
---------- - -
1 A C
1 B
2 A C
2 B

How to do select count(*) group by and select * at same time?

For example, I have table:
ID | Value
1 hi
1 yo
2 foo
2 bar
2 hehe
3 ha
6 gaga
I want my query to get ID, Value; meanwhile the returned set should be in the order of frequency count of each ID.
I tried the query below but don't know how to get the ID and Value column at the same time:
SELECT COUNT(*) FROM TABLE group by ID order by COUNT(*) desc;
The count number doesn't matter to me, I just need the data to be in such order.
Desire Result:
ID | Value
2 foo
2 bar
2 hehe
1 hi
1 yo
3 ha
6 gaga
As you can see because ID:2 appears most times(3 times), it's first on the list,
then ID:1(2 times) etc.
you can try this -
select id, value, count(*) over (partition by id) freq_count
from
(
select 2 as ID, 'foo' as value
from dual
union all
select 2, 'bar'
from dual
union all
select 2, 'hehe'
from dual
union all
select 1 , 'hi'
from dual
union all
select 1 , 'yo'
from dual
union all
select 3 , 'ha'
from dual
union all
select 6 , 'gaga'
from dual
)
order by 3 desc;
select t.id, t.value
from TABLE t
inner join
(
SELECT id, count(*) as cnt
FROM TABLE
group by ID
)
x on x.id = t.id
order by x.cnt desc
How about something like
SELECT t.ID,
t.Value,
c.Cnt
FROM TABLE t INNER JOIN
(
SELECT ID,
COUNT(*) Cnt
FROM TABLE
GROUP BY ID
) c ON t.ID = c.ID
ORDER BY c.Cnt DESC
SQL Fiddle DEMO
I see the question is already answered, but since the most obvious and most simple solution is missing, I'm posting it anyway. It doesn't use self joins nor subqueries:
SQL> create table t (id,value)
2 as
3 select 1, 'hi' from dual union all
4 select 1, 'yo' from dual union all
5 select 2, 'foo' from dual union all
6 select 2, 'bar' from dual union all
7 select 2, 'hehe' from dual union all
8 select 3, 'ha' from dual union all
9 select 6, 'gaga' from dual
10 /
Table created.
SQL> select id
2 , value
3 from t
4 order by count(*) over (partition by id) desc
5 /
ID VALU
---------- ----
2 bar
2 hehe
2 foo
1 yo
1 hi
6 gaga
3 ha
7 rows selected.