select *
from Address
where city in ('a', 'b', 'c', 'd', 'e', 'f', ... )
How can I modify the SQL to get only the cities provided in the query that are missing in the above result?
For example: I've 100 cities in the in-clause (hard-coded) and I want to see which cities that I passed in are not in the Address table.
You can use union to build table of cities and then minus operator.
select 'Dallas' as city from dual union all
select 'Berlin' as city from dual union all
select 'Cracow' as city from dual union all
select 'Praha' as city from dual
minus
select city from address
Instead of union you can use predefined type odcivarchar2list, which shortens syntax:
select column_value as city
from table(sys.odcivarchar2list('Dallas', 'Berlin', 'Cracow', 'Praha'))
minus
select city from address
... and instead of minus You can use joins or not in or not exists.
Test data and output of both queries:
create table address (id number, city varchar2(10));
insert into address values (1, 'Rome');
insert into address values (2, 'Dallas');
insert into address values (3, 'Cracow');
insert into address values (4, 'Moscow');
insert into address values (5, 'Liverpool');
insert into address values (6, 'Cracow');
insert into address values (7, 'Seoul');
CITY
------------
Berlin
Praha
Looks like you are looking for all addresses which is not available in the given list. You can use 'not in'
select * from Address where city not in
('a',
'b',
'c',
'd',
'e',
'f'
..
)
Related
I have the following schema:
CREATE TABLE table1
(
user,
phoneType, --from ['A','B','C','D', 'E'], user can have any number of any type
uniquePhoneID, --unique string identifying the phone
day_id --date; record does not necessarily exist for every seen user + phoneType every day, represented as number in example
);
INSERT INTO table1
VALUES (1, 'A', xyz, 1),
(1, 'A', abc, 1),
(1, 'B', def, 2),
(1, 'A', xyz, 2),
(1, 'C', hij, 4),
(1, 'A' xyz, 5),
(2, 'C', w, 9),
(2, 'D', z, 10),
(2, 'A', p, 10),
(2, 'E', c, 11),
(3, 'A', r, 19),
(3, 'B', q, 19),
(3, 'B', q, 20),
(3, 'B', f, 20),
(3, 'B', y, 21);
A single user, uniquePhoneID, day_id will only show up at most once, but not necessarily at all on any given day.
I am looking to concatenate each user in the table with their 4 phoneTypes in alphabetical order, so the result is as follows:
1 | AABC
2 | ACDE
3 | ABBB
I have tried a few different ways of doing this but I am unsure how to get the answer I am looking for.
I think user is a reserved word, so you will have to resolve that. Otherwise, I think something like this will work for you:
select user, string_agg (phonetype, '' order by phonetype)
from table1
group by user
-- EDIT 4/21/2022 --
Aah, okay. I did not glean that from the original question.
What if you used the distinct on the original table before the aggregation?
select userid, string_agg (phonetype, '' order by phonetype)
from (select distinct userid, phonetype, uniquephoneid from table1) x
group by userid
I got these results from this version:
1 AABC
2 ACDE
3 ABBB
If that logic still doesn't work, can you alter the sample data to find an example where it fails?
I have a table like this:
enter image description here
Now, I have get all rows formatnbr = 101 using regexp_like(nbr, expression). I'm using regexp_like (nbr, '^\d((\d)1(\1)2(\1)3)') but I have to write 7 expression with 'OR' in where clause:
select * from tbl where regexp(nbr, '^\d((\d)1(\1)2(\1)3)') or regexp(nbr, '^\d((\d)2(\1)3(\1)4)') or ...
How do I using 1 format likely in description column: regexp_like(nbr, '^\dxyx(y+1)x(y+2)') to select? Help me please!
Output:
enter image description here
create table tbl
(
formatnbr NUMBER not null,
nbr VARCHAR2(7),
description VARCHAR2(50)
);
insert into tbl(formatnbr, nbr, description) values (100, '8123456', 'Dx(x+1)(x+2)(x+3)(x+4)(x+5)');
insert into tbl(formatnbr, nbr, description) values (101, '8111213', 'Dxyx(y+1)x(y+2)');
insert into tbl(formatnbr, nbr, description) values (100, '7456789', 'Dx(x+1)(x+2)(x+3)(x+4)(x+5)');
insert into tbl(formatnbr, nbr, description) values (101, '9232425', 'Dxyx(y+1)x(y+2)');
insert into tbl(formatnbr, nbr, description) values (101, '5565758', 'Dxyx(y+1)x(y+2)');
insert into tbl(formatnbr, nbr, description) values (100, '0456789', 'Dx(x+1)(x+2)(x+3)(x+4)(x+5)');
insert into tbl(formatnbr, nbr, description) values (101, '1454647', 'Dxyx(y+1)x(y+2)');
commit;
Thanks,
For:
Dx(x+1)(x+2)(x+3)(x+4)(x+5) you can list the possible values as:
012345|123456|234567|345678|456789
Dxyx(y+1)x(y+2) you can list the possible y values and use backreferences to match the x values as
(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)
So your inserts would be:
create table tbl
(
formatnbr NUMBER not null,
nbr VARCHAR2(7),
description VARCHAR2(110)
);
insert into tbl(formatnbr, nbr, description)
SELECT 100, '8123456', '012345|123456|234567|345678|456789' FROM DUAL UNION ALL
SELECT 101, '8111213', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL UNION ALL
SELECT 100, '7456789', '012345|123456|234567|345678|456789' FROM DUAL UNION ALL
SELECT 101, '9232425', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL UNION ALL
SELECT 101, '5565758', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL UNION ALL
SELECT 100, '0456789', '012345|123456|234567|345678|456789' FROM DUAL UNION ALL
SELECT 101, '1454647', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL;
db<>fiddle here
Please help with SQL query. I've got a table:
CREATE TABLE PCDEVUSER.tabletest
(
id INT PRIMARY KEY NOT NULL,
name VARCHAR2(64),
pattern INT DEFAULT 1 NOT NULL,
tempval INT
);
Let's pretend it was filled with values:
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (1, 'A', 1, 10);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (2, 'A', 1, 20);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (3, 'A', 2, 10);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (5, 'A', 2, 20);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (4, 'A', 2, 30);
And I need to update all records (grouped by pattern) with NO MAX value TEMPVALUE. So as result I have to update records with Ids (1, 3, 5). Records with IDs (2, 4) has max values in there PATTERN group.
HELP PLZ
This select statement will help you get the IDs you need :
SELECT
*
FROM
(SELECT
id
,name
,pattern
,tempval
,MAX(tempval) OVER (PARTITION BY pattern) max_tempval
FROM
tabletest
)
WHERE 1=1
AND tempval != max_tempval
;
You should be able to build an update statement around that easily enough
Something like this:
update tabletest t
set ????
where t.tempval < (select max(tempval) from tabletest tt where tt.pattern = t.pattern);
It is unclear what values you want to set. The ???? is for the code that sets the values.
In SQL Server 2008 I have a table People (Id, Gender, Name).
Gender is either Male or Female. There can be many people with the same name.
I would like to write a query that displays for each gender the top 2 names
by count and their count, like this:
Male Female
Adam 23 Rose 34
Max 20 Jenny 15
I think that PIVOT might be used but all the examples I have seen display only one column for each header.
Here is an example on SQL Fiddle -- http://sqlfiddle.com/#!3/b3477/1
This uses an couple of common table expressions to separate the genders.
create table People
(
Id int,
Gender varchar(50),
Name varchar(50)
)
;
insert into People values (1, 'Male', 'Bob');
insert into People values (2, 'Male', 'Bob');
insert into People values (3, 'Male', 'Bill');
insert into People values (4, 'Male', 'Chuck');
insert into People values (5, 'Female', 'Anne');
insert into People values (6, 'Female', 'Anne');
insert into People values (7, 'Female', 'Bobbi');
insert into People values (8, 'Female', 'Jane');
with cteMale as
(
select Name as 'MaleName', Count(*) as Num, ROW_NUMBER() over(order by count(*) desc, Name) RowNum
from People
where Gender = 'Male'
group by Name
)
,
cteFemale as
(
select top 2 Name as 'FemaleName', Count(*) as Num, ROW_NUMBER() over(order by count(*) desc, Name) RowNum
from People
where Gender = 'Female'
group by Name
)
select a.MaleName, a.Num as MaleNum, b.femaleName, b.Num as FemaleNum
from cteMale a
join cteFemale b on
a.RowNum = b.RowNum
where a.RowNum <= 2
Use a windowing function. Below is a complete solution using a temporary table #people.
-- use temp db
use tempdb;
go
-- drop test table
--drop table #people;
--go
-- create test table
create table #people (my_id int, my_gender char(1), my_name varchar(25));
go
-- clear test table
delete from #people;
-- three count
insert into #people values
(23, 'M', 'Adam'),
(34, 'F', 'Rose');
go 3
-- two count
insert into #people values
(20, 'M', 'Max'),
(15, 'F', 'Jenny');
go 2
-- one count
insert into #people values
(20, 'M', 'John'),
(15, 'F', 'Julie');
go
-- grab top two by gender
;
with cte_Get_Top_Two as
(
select ROW_NUMBER() OVER(PARTITION BY my_gender ORDER BY count() DESC) AS my_window,
my_gender, my_name, count() as total
from #people
group by my_gender, my_name
)
select * from cte_Get_Top_Two where my_window in (1, 2)
go
Here is the output.
PS: You can drop my_id from the table since it does not relate to your problem but does not change solution.
I an trying to INSERT multiple rows into an SQL, Oracle table though SQL Developer v3.0.04
the Database was set-up by Uni so I don't know what version it is.
after looking on-line I have come up with the code below but it will not INSERT any data. I have tested the insert with just one row and that is OK. What am I missing?
Insert all
Into Patient Values
('101', '1 house', Null, 'Kingston', 'Surrey', 'KT1 1XX', '10/jan/1980', 'm', 01452987456)
Into Patient Values
('102', '2 egg rd', 'vail', 'guildford', 'Surrey', 'GU1 1LL', '05/dec/1985', 'm', 01452987456)
Into Patient Values
('103', '6 station rd', Null, 'guildford', 'Surrey', 'GU1 2XX', '15/may/1990', 'f', 01452987456)
Select * from Patient;
INSERT ALL has two different uses. One is to insert different sub-sets of selected columns into a table. The other is to direct rows into different according to certain criteria. In both cases the data comes from a SELECT clause rather than from VALUES. See the examples in the documentation.
Normally, you would simply write multiple INSERT statements potentially in a single PL/SQL block. Something like
begin
Insert Into Patient Values
('101', '1 house', Null, 'Kingston', 'Surrey', 'KT1 1XX', '10/jan/1980', 'm', 01452987456);
Insert Into Patient Values
('102', '2 egg rd', 'vail', 'guildford', 'Surrey', 'GU1 1LL', '05/dec/1985', 'm', 01452987456);
Insert Into Patient Values
('103', '6 station rd', Null, 'guildford', 'Surrey', 'GU1 2XX', '15/may/1990', 'f', 01452987456);
end;
/
If you really want to do this in a single SQL statement, you can do an INSERT ... SELECT but that's generally going to be more complex than using three separate statements.
insert into patient
select *
from (select '101' id, '1 house' addr, null col1, 'Kingston' city, ...
from dual
union all
select '102', '2 egg rd', 'vail', 'guildford', 'Surrey', 'GU1 1LL', '05/dec/1985', 'm', 01452987456
from dual
union all
select '103', '6 station rd', Null, 'guildford', 'Surrey', 'GU1 2XX', '15/may/1990', 'f', 01452987456
from dual)
I would also caution you to use proper data types and to specify the column names in your INSERT statement. I'm guessing, for example, that the first column of Patient table is some sort of PatientID that is defined as a NUMBER. If so, you'd really want to insert a number rather than a character string. Similarly, the seventh column with values like '15/may/1990' is probably defined as a DATE in the table. If so, your INSERT should insert a DATE not a character string by either explicitly calling TO_DATE with a particular format mask or by using the ANSI date format, i.e. date '1980-01-10'. And if you want the last column to retain the leading 0, you'll need to ensure that the column in the database is defined as a VARCHAR2 and that you insert a character string rather than a number.
Interesting. It is possible to use insert all to insert multiple rows as you are attempting. Not that I would recommend doing so over Justin's suggested solutions.
The syntax diagram for multi-table insert indicates that a subquery is always required. However, you don't have to use any of the results of the subquery:
SQL> drop table t;
Table dropped.
SQL> create table t (c1 number, c2 varchar2(10));
Table created.
SQL> insert all into t (c1, c2) values (1, 'one')
2 into t (c1, c2) values (2, 'two')
3 select * from dual;
2 rows created.
SQL> select * from t;
C1 C2
---------- ----------
1 one
2 two
The two into ... values(...) will cause two rows to be inserted per row in the the subquery:
SQL> insert all into t (c1, c2) values (1, 'one')
2 into t (c1, c2) values (2, 'two')
3 select * from dual
4 connect by level <= 10;
20 rows created.
Replace this query [ Select * from Patient; ] with
Select * from dual;
dual is a virtual table which is not existing in our schema but it can be existed as a part of Oracle perspective in RAM not in our storage
Insert all
Into Patient Values
('101', '1 house', Null, 'Kingston', 'Surrey', 'KT1 1XX', '10/jan/1980', 'm', 01452987456)
Into Patient Values
('102', '2 egg rd', 'vail', 'guildford', 'Surrey', 'GU1 1LL', '05/dec/1985', 'm', 01452987456)
Into Patient Values
('103', '6 station rd', Null, 'guildford', 'Surrey', 'GU1 2XX', '15/may/1990', 'f', 01452987456)
Select * from dual;