Apply a select for every element of a column - sql

I would like to update third with a select that uses column first
|first #|second #|third #|
|_______|________|_______|
|___1___|___1____|_null__|
|___5___|___2____|_null__|
|___3___|___6____|_null__|
|___2___|___4____|_null__|
In pseudo code:
for row in table:
row.third = result_of_a_select(row.first)
What is the equivalent on SQL?
My wrong attempt:
update example_table
set third=
(
SELECT MAX(CDARTI) FROM
(
SELECT A.CDARTI
FROM PGMR.UT_ART_CODALT T,
PGMR.MRP_ARCH_ARTICOLI A
WHERE
A.CDARTI = T.CDARTI AND
T.CDARTI = first
UNION
SELECT A.CDARTI
FROM PGMR.UT_ART_CODALT T,
PGMR.MRP_ARCH_ARTICOLI A
WHERE
A.CDARTI = T.CDARTI_A AND
T.CDARTI = first
UNION
SELECT A.CDARTI
FROM PGMR.UT_ART_CODALT T,
PGMR.MRP_ARCH_ARTICOLI A
WHERE
A.CDARTI = T.CDARTI AND
T.CDARTI_A = first
UNION
SELECT A.CDARTI
FROM PGMR.UT_ART_CODALT T,
PGMR.MRP_ARCH_ARTICOLI A
WHERE
A.CDARTI = T.CDARTI_A AND
T.CDARTI = (SELECT T2.CDARTI FROM PGMR.UT_ART_CODALT T2 WHERE T2.CDARTI_A = first)
)
);
commit;

Works for me.
update t1 set third = (select third from t2 where t2.first = t1.first);
Fiddle (switched to MySql DB since I can't make Oracle work in it, but tested against my local Oracle as well).
The problem is not in the approach, but in your query. To fix that, you'll need to provide a Minimal, Complete, and Verifiable example.

A simplified test case:
SQL> create table yourTable (first, second, third) as (
2 select 1, 1, cast (null as number) from dual union all
3 select 5, 2, cast (null as number) from dual union all
4 select 3, 6, cast (null as number) from dual union all
5 select 2, 4, cast (null as number) from dual
6 );
Table created.
SQL> update yourTable t
2 set third = (select t.first * 2 from dual);
4 rows updated.
SQL> select * from yourTable;
FIRST SECOND THIRD
---------- ---------- ----------
1 1 2
5 2 10
3 6 6
2 4 4
SQL>

To make it a slightly more interesting/illustrative example I'm updating the third column with the value from a mapping table and have included duplicate values.
You can use MERGE and match on the pseudocolumn ROWID:
Oracle Setup:
CREATE TABLE table_name ( first, second, third ) AS
SELECT 1, 1, CAST( NULL AS NUMBER ) FROM DUAL UNION ALL
SELECT 5, 2, NULL FROM DUAL UNION ALL
SELECT 3, 6, NULL FROM DUAL UNION ALL
SELECT 2, 4, NULL FROM DUAL UNION ALL
SELECT 3, 4, NULL FROM DUAL;
CREATE TABLE table_name_map ( first, value ) AS
SELECT 1, 9 FROM DUAL UNION ALL
SELECT 2, 8 FROM DUAL UNION ALL
SELECT 3, 7 FROM DUAL UNION ALL
SELECT 4, 6 FROM DUAL UNION ALL
SELECT 5, 5 FROM DUAL;
Update:
MERGE INTO table_name dst
USING ( SELECT t.ROWID AS ri,
m.value
FROM table_name t
INNER JOIN table_name_map m
ON ( t.first = m.first )
) src
ON ( src.ri = dst.ROWID )
WHEN MATCHED THEN
UPDATE SET third = src.value;
Result:
FIRST SECOND THIRD
----- ------ -----
1 1 9
5 2 5
3 6 7
2 4 8
3 4 7

Related

How to find duplicate values according multiple columns and show both

I try to find another examples, but I have not been able to find one that can help me
I am currently trying to find if the value in the STR_ROUTE column is in the STR_STREET column, as shown in the following example
ID
STR_ROUTE
STR_STREET
1
MAIN
Can
2
AV
CAL
3
CLL
CLL
4
STR
VAL
5
VAL
MIN
7
CAL
SQR
in this example as the CAL and VAL values of the STR_ROUTE column are in STR_STREET the expected result is to display the following table with all occurrences
ID
STR_ROUTE
STR_STREET
2
AV
CAL
4
STR
VAL
5
VAL
MIN
7
CAL
SQR
(The third row is not taken into consideration because it is the same registry.)
I was validating with this option, but I have not been able to succeed and does not take the rules into consideration.
It does not take into consideration if the repeated value is within
the same record.
Both the repeated record and the record to which it is compared must be displayed.
SELECT * FROM TABLE WHERE STR_ROUTE IN (SELECT STR_STREET FROM TABLE WHERE STR_STREET)
You may check the presence of values of each column in another column and union the results.
with test_table(ID, STR_ROUTE, STR_STREET) as (
select 1, 'MAIN', 'Can' from dual union all
select 2, 'AV', 'CAL' from dual union all
select 3, 'CLL', 'CLL' from dual union all
select 4, 'STR', 'VAL' from dual union all
select 5, 'VAL', 'MIN' from dual union all
select 7, 'CAL', 'SQR' from dual
)
select *
from test_table
where str_route in (
select f.str_street
from test_table f
)
and str_route != str_street
union all
select *
from test_table
where str_street in (
select f.str_route
from test_table f
)
and str_route != str_street
ID
STR_ROUTE
STR_STREET
5
VAL
MIN
7
CAL
SQR
2
AV
CAL
4
STR
VAL
db<>fiddle here
You can use a hierarchical query and filter to only include the rows where the hierarchical query has descended to the second level and it is a leaf node or where the first level of the hierarchy is not a leaf (and there is a matching second level in the hierarchy):
SELECT *
FROM table_name
WHERE LEVEL = 1 AND CONNECT_BY_ISLEAF = 0
OR LEVEL = 2 AND CONNECT_BY_ISLEAF = 1
CONNECT BY NOCYCLE
PRIOR str_route = str_street;
Which, for the sample data:
CREATE TABLE table_name (ID, STR_ROUTE, STR_STREET) AS
SELECT 1, 'MAIN', 'Can' FROM DUAL UNION ALL
SELECT 2, 'AV', 'CAL' FROM DUAL UNION ALL
SELECT 3, 'CLL', 'CLL' FROM DUAL UNION ALL
SELECT 4, 'STR', 'VAL' FROM DUAL UNION ALL
SELECT 5, 'VAL', 'MIN' FROM DUAL UNION ALL
SELECT 7, 'CAL', 'SQR' FROM DUAL;
Outputs:
ID
STR_ROUTE
STR_STREET
5
VAL
MIN
4
STR
VAL
7
CAL
SQR
2
AV
CAL
db<>fiddle here

select only those users whose contacts length is not 5

I have table like this:
id
name
contact
1
A
65489
1
A
1
A
45564
2
B
3
C
12345
3
C
1234
4
D
32
4
D
324
I only want users who have no contact or the contact length is not five.
If the user has two or more contacts and the length of one of them is five and the rest is not, then such users should not be included in the table.
so,If the customer has at least one contact length of five, I do not want that.
so, i want table like this:
id
name
contact
2
B
4
D
32
4
D
324
Can you halp me?
You could actually do a range check here:
SELECT id, name, contact
FROM yourTable t1
WHERE NOT EXISTS (
SELECT 1
FROM yourTable t2
WHERE t2.id = t1.id AND TO_NUMBER(t2.contact) BETWEEN 10000 AND 99999
);
Note that if contact already be a numeric column, then just remove the calls to TO_NUMBER above and compare directly.
Yet another option:
SQL> with test (id, name, contact) as
2 (select 1, 'a', 65879 from dual union all
3 select 1, 'a', null from dual union all
4 select 1, 'a', 45564 from dual union all
5 select 2, 'b', null from dual union all
6 select 3, 'c', 12345 from dual union all
7 select 3, 'c', 1234 from dual union all
8 select 4, 'd', 32 from dual union all
9 select 4, 'd', 324 from dual
10 )
11 select *
12 from test a
13 where exists (select null
14 from test b
15 where b.id = a.id
16 group by b.id
17 having nvl(max(length(b.contact)), 0) < 5
18 );
ID N CONTACT
---------- - ----------
2 b
4 d 32
4 d 324
SQL>
COUNT analytic function can also be used to get the job done.
select id, name, contact
from (
select id, name, contact
, count( decode( length(contact), 5, 1, null ) ) over( partition by id, name ) cnt
from YourTable
)
where cnt = 0
demo

using regular expression that not include string '05613'. have NAW_05613_11_PL04_02 in table. need condition rows which have 05613 not be displayed

I want to fetch data from database using regular expression which should not include string '05613'.
I have values like NAW_05613_11_PL04_02 in my table. I want to give condition that all rows which have 05613 in it should not be displayed.
I have tried using REGEXP_LIKE(d.variable_value_string, '^N(*)[^{05613}](*)')
SELECT * from tablename where REGEXP_LIKE(columnname, '^N(*)[^{05613}](*)')
Expected result should be- row with value having 05613 should not be retrieved.
A simple LIKE could be enough:
... columnName not like '%05613%'
For example:
SQL> with test(c) as (
2 select '05613XX' from dual union all
3 select 'XX05613' from dual union all
4 select 'X05613X' from dual union all
5 select 'XXX' from dual
6 )
7 select *
8 from test
9 where c not like '%05613%';
C
-------
XXX
SQL>
If you need, for some reason, regexp_like, this is a way:
SQL> with test(c) as (
2 select '05613XX' from dual union all
3 select 'XX05613' from dual union all
4 select 'XX05613' from dual union all
5 select 'X05613X' from dual union all
6 select 'XXX' from dual
7 )
8 select *
9 from test
10 where not regexp_like(c, '05613');
C
-------
XXX
If this is your assignment and usage of regexp_like is mandated then use following regexp_like:
SELECT * from tablename D
where Not REGEXP_LIKE(d.variable_value_string, '05613')
Cheers!!

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.)

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.