oracle database, insert data - database

I'm using Oracle 11g table:
create or replace type address as object (
street varchar2(20),
city varchar2(10),
p_code varchar2(8)
) not final;
/
create or replace type name as object (
title varchar2(5),
firstName varchar2(8),
surname varchar2(8)
) not final;
/
create or replace type phone as object
(
homePhone int,
mobile1 int,
mobile2 int
) not final;
/
create or replace type person as object (
pname name,
pAddress address,
Pphone phone
) not final;
/
create or replace type employee under person (
empId varchar2(5),
position varchar2(16),
salary int,
joinDate date,
supervisor ref employee);
/
create table tb_employee of employee
(
primary key(empID)
)
/
data I insert
insert into tb_employee values
(
person(name('mr','jone','smith'),address('street','city','post
code'),phone('11111111111','22222222222','33333333333')),
position('head'),
salary(1111),
joinDate(12-Feb-1994),
empID('001')
)
insert into tb_employee values
(
person(name('mr','jane','smith'),address('street','city','post
code'),phone('11111111111','22222222222','33333333333')),
position('accountant'),
salary(2222,
joinDate(13-Feb-1995),
empID('002')
)
insert into tb_employee values
(
person(name('miss','ross','smith'),address('street','city','post
code'),phone('11111111111','22222222222','33333333333')),
position(manager),
salary(333),
joinDate(14-Feb-1996),
empID('003')
)
I would like to insert supervisor to data by using reference function,
for example:
for head (jone smith) is a supervisor or a manager (miss ross smith),
manager(miss ross smith) is a supervisor of account(Mr jane smith),
thanks!

You are inserting records of employee type: that applies to the whole record so you need to write a VALUES clause which matches the projection of that type.
To populate the REF clause you need to select the reference of the pertinent object. Your first record doesn't have a supervisor, so we pass NULL in this case:
insert into tb_employee values
( employee(
name('mr','jone','smith')
, address('street','city','postcode')
, phone('11111111111','22222222222','33333333333')
, '001' -- emp id
, 'head' -- position
, 11111 -- salary
, to_date('12-Feb-1994','dd-mon-yyyy') -- joinDate
, null-- supervisor
))
/
For the other records we use the INSERT ... SELECT ... FROM syntax:
insert into tb_employee
select
employee(
name('mr','jane','smith')
, address('street','city','postcode')
, phone('11111111111','22222222222','33333333333')
, '002' -- emp id
, 'accountant' -- position
, 2222 -- salary
, to_date('13-Feb-1995','dd-mon-yyyy') -- joinDate
, ref (m) -- supervisor
)
from tb_employee m
where m.empid = '001'
/
insert into tb_employee
select
employee(
name('miss','ross','smith')
, address('street','city','postcode')
, phone('11111111111','22222222222','33333333333')
, '003' -- emp id
, 'manager' -- position
, 333 -- salary
, to_date('14-Feb-1996','dd-mon-yyyy') -- joinDate
, ref (m) -- supervisor
)
from tb_employee m
where m.empid = '002'
/
Here is a Oracle LiveSQL demo (free OTN account required). (It's a shame that Oracle's developer Cloud can't handle user-defined types nicely.)

Related

Rename column name based on the Value

I need to rename the column base on the value I give in it.
SELECT TOP 1
[Pratice_Id] = [OID]// id
, [Province] = '' //province
, [Country] = 'US'// country
FROM [tbl_Office]
if the country equals to US I want to change columnName [Province] to State
I would strongly suggest a column STATE_PROVINCE, however, if you MUST and you are not opposed to a temp table, perhaps something like this
Example
Select Top 1 *
Into #Temp
From YourTable
Where ...
Order By ...
If ( Select Top 1 Country From #Temp ) = 'US'
Select [Pratice_Id]
,[State] = [Province]
,[Country]
From #Temp
Else
Select * from #Temp
Returns
Pratice_Id State Country
1 RI US
Personally, I would provide both
Declare #YourTable table ([Pratice_Id] int,[Province] varchar(50),[Country] varchar(50))
Insert Into #YourTable values
(1,'RI','US')
,(2,'Alberta','Canada')
Select [Pratice_Id]
,[State] = case when [Country]='US' then Province else '' end
,[Province] = case when [Country]<>'US' then Province else '' end
,[Country]
From #YourTable
Returns
Pratice_Id State Province Country
1 RI US
2 Alberta Canada

How to get desired result in SQL Server

In my application there is a table to store text and another table to store it's respective images..
My table structure goes as follows (tbl_article):
article_id | Page_ID | article_Content
-----------+---------+-----------------
1 | 1 | hello world
2 | 1 | hello world 2
where article_id is the pk and auto incremented.
Now in my other table (tbl_img):
image_id| image_location|article_id | page_id
--------+---------------+-----------+---------
1 | imgae locat | 1 | 1
2 | image loc2 | 2 | 1
where image_id is the pk and auto incremented.
In both table I am inserting data through table valued parameter, and in second table article_id is referencing article_id of the first table.
To get auto incremented column value I am using output clause:
DECLARE #TableOfIdentities TABLE
(
IdentValue INT,
PageId INT
)
INSERT INTO tbl_article(page_id, article_content)
OUTPUT Inserted.article_id, #pageId INTO #TableOfIdentities (IdentValue, PageId)
SELECT page_id, slogan_body_header
FROM #dtPageSlogan
INSERT INTO tbl_img(page_id, image_location)
SELECT page_id, image_location
FROM #dtPageImageContent
But now I have to insert values from #TableOfIdentities into article_id of tbl_img - how to do that?
You need an additional column , a temporary article id generated from your code to link images and related articles properly. So you can use MERGE with OUTPUT, because with merge you can refer to columns from both the target and the source and build your TableOfIdentities tvp properly, then join it with dtPageImageContent to insert on tbl_img.
CREATE TABLE tbl_article (
article_id INT IDENTITY(1, 1) PRIMARY KEY
, Page_ID INT
, article_Content NVARCHAR(MAX)
);
CREATE TABLE tbl_img (
image_id INT IDENTITY(1, 1) PRIMARY KEY
, image_location VARCHAR(256)
, article_id INT
, Page_ID INT
);
DECLARE #TableOfIdentities TABLE
(
IdentValue INT,
PageId INT,
tmp_article_id INT
);
DECLARE #dtPageSlogan TABLE(
tmp_article_id INT -- generated in your code
, page_id INT
, slogan_body_header NVARCHAR(MAX)
);
DECLARE #dtPageImageContent TABLE (
page_id INT
, image_location VARCHAR(256)
, tmp_article_id INT -- needed to link each image to its article
)
-- create sample data
INSERT INTO #dtPageSlogan(tmp_article_id, page_id, slogan_body_header)
VALUES (10, 1, 'hello world');
INSERT INTO #dtPageSlogan(tmp_article_id, page_id, slogan_body_header)
VALUES (20, 1, 'hello world 2');
INSERT INTO #dtPageImageContent(page_id, image_location, tmp_article_id)
VALUES (1, 'image loc1', 10);
INSERT INTO #dtPageImageContent(page_id, image_location, tmp_article_id)
VALUES (1, 'image loc2', 20);
-- use merge to insert tbl_article and populate #TableOfIdentities
MERGE INTO tbl_article
USING (
SELECT ps.page_id, ps.slogan_body_header, ps.tmp_article_id
FROM #dtPageSlogan as ps
) AS D
ON 1 = 2
WHEN NOT MATCHED THEN
INSERT(page_id, article_content) VALUES (page_id, slogan_body_header)
OUTPUT Inserted.article_id, Inserted.page_id, D.tmp_article_id
INTO #TableOfIdentities (IdentValue, PageId, tmp_article_id)
;
-- join using page_id and tmp_article_id fields
INSERT INTO tbl_img(page_id, image_location, article_id)
-- select the "IdentValue" from your table of identities
SELECT pic.page_id, pic.image_location, toi.IdentValue
FROM #dtPageImageContent pic
-- join the "table of identities" on the common "page_id" column
INNER JOIN #TableOfIdentities toi
ON pic.page_Id = toi.PageId AND pic.tmp_article_id = toi.tmp_article_id
;
You can try it on fiddle
You need to join the #dtPageImageContent table variable with the #TableOfIdentities table variable on their common page_id to get those values:
-- add the third column "article_id" to your list of insert columns
INSERT INTO tbl_img(page_id, image_location, article_id)
-- select the "IdentValue" from your table of identities
SELECT pic.page_id, pic.image_location, toi.IdentValue
FROM #dtPageImageContent pic
-- join the "table of identities" on the common "page_id" column
INNER JOIN #TableOfIdentities toi ON pic.page_Id = toi.page_id

Matching in 2 Waves. Second "Wave" is based on First "Wave"

I have a "matching" scenario where I need to match records from a table.
I've altered my situation to use the Northwind database .. for illustration purposes.
Given a "set" of data (put in my #holder table below), I need to find matches based on the following criteria.
If both lastname and firstname match, match on TWO or more of the following : (city-state-together OR zip) , phone, extension
If one of either lastname OR firstname match, match on THREE or more of the following : (city-state-together OR zip) , phone,
extension
Note that "city-state-together OR zip" means that I need to match on the combination of city-and-state ........ or zip..........and if all three match, (city-state-and-zip), that should still only count as "1" for the "(ColumnCityStateZipEnum + ColumnHomePhoneEnum + ColumnExtensionEnum)" calculation.
I've come up with the below. But I have 7 left joins.
Is there another way to do this kind of problem in SQL?
Use Northwind /* Or NorthwindPartial */
GO
declare #holder table ( holderidentitykey int identity (1,1), lastname varchar(32) , firstname varchar(48) , city varchar(32) , stateabbr varchar(32) , zip varchar(5) , homephone varchar(16) , extension varchar(8) )
insert into #holder ( lastname , firstname , city , stateabbr, zip, homephone , extension )
select null , null, null, null, null , null, null
union all select 'Davolio' , 'Nancy', null, null, '98122' , '(206) 555-9857', null /* should 'match'. lastname, firstname and TWO of the other data-elements */
union all select 'Davolio' , null, null, null, null , null, null
union all select 'Fuller' , 'Andrew', 'Tacoma', 'WA', null , null, null
union all select 'Peacock' , 'MaggyNotAMatchNoPhone', 'Redmond', 'WA', '98052' , null, null
union all select 'Peacock' , 'MaggyNotAMatchWithPhoneAndExtension', 'Redmond', 'WA', '98052' , '(206) 555-8122', '5176' /* should 'match'. lastname and THREE of the other data-elements */
/*
If both lastname and firstname match, match on TWO or more of the following : (city-state-together OR zip) , phone, extension
If one of either lastname OR firstname match, match on THREE or more of the following : (city-state-together OR zip) , phone, extension
*/
select distinct * from
(
select
holderidentitykey,
ColumnLastNameFirstNameEnum =
case
when h.lastname = eLastName.LastName and h.firstname = eFirstName.FirstName then 2
when h.lastname = eLastName.LastName then 1
when h.firstname = eFirstName.FirstName then 1
else 0
end
,
ColumnCityStateZipEnum =
case
when h.zip = eZip.PostalCode then 1
when h.city = eCity.City and h.stateabbr = eState.Region then 1
else 0
end
,
ColumnHomePhoneEnum =
case
when h.homephone = eHomePhone.HomePhone then 1
else 0
end
,
ColumnExtensionEnum =
case
when h.extension = eExtension.Extension then 1
else 0
end
, eLastName.LastName , eFirstName.FirstName, eZip.PostalCode, eCity.City, eState.Region, eHomePhone.HomePhone, eExtension.Extension
from
#holder h
left join dbo.Employees eLastName on h.lastname = eLastName.LastName
left join dbo.Employees eFirstName on h.firstname = eFirstName.FirstName
left join dbo.Employees eZip on h.zip = eZip.PostalCode
left join dbo.Employees eCity on h.city = eCity.City
left join dbo.Employees eState on h.stateabbr = eState.Region
left join dbo.Employees eHomePhone on h.homephone = eHomePhone.HomePhone
left join dbo.Employees eExtension on h.extension = eExtension.Extension
) as derived1
where
derived1.ColumnLastNameFirstNameEnum >= 2 and (ColumnCityStateZipEnum + ColumnHomePhoneEnum + ColumnExtensionEnum) >= 2
OR
derived1.ColumnLastNameFirstNameEnum >= 1 and (ColumnCityStateZipEnum + ColumnHomePhoneEnum + ColumnExtensionEnum) >= 3
-- select * from dbo.Employees e
Here is a "partial" Northwind creation if you don't have one handy.
SET NOCOUNT ON
GO
USE master
GO
if exists (select * from sysdatabases where name='NorthwindPartial')
drop database NorthwindPartial
go
DECLARE #device_directory NVARCHAR(520)
SELECT #device_directory = SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1)
FROM master.dbo.sysaltfiles WHERE dbid = 1 AND fileid = 1
EXECUTE (N'CREATE DATABASE NorthwindPartial
ON PRIMARY (NAME = N''NorthwindPartial'', FILENAME = N''' + #device_directory + N'northwndPartial.mdf'')
LOG ON (NAME = N''NorthwindPartial_log'', FILENAME = N''' + #device_directory + N'northwndPartial.ldf'')')
go
GO
set quoted_identifier on
GO
/* Set DATEFORMAT so that the date strings are interpreted correctly regardless of
the default DATEFORMAT on the server.
*/
SET DATEFORMAT mdy
GO
use "NorthwindPartial"
go
if exists (select * from sysobjects where id = object_id('dbo.Employees') and sysstat & 0xf = 3)
drop table "dbo"."Employees"
GO
CREATE TABLE "Employees" (
"EmployeeID" "int" IDENTITY (1, 1) NOT NULL ,
"LastName" nvarchar (20) NOT NULL ,
"FirstName" nvarchar (10) NOT NULL ,
"Title" nvarchar (30) NULL ,
"TitleOfCourtesy" nvarchar (25) NULL ,
"BirthDate" "datetime" NULL ,
"HireDate" "datetime" NULL ,
"Address" nvarchar (60) NULL ,
"City" nvarchar (15) NULL ,
"Region" nvarchar (15) NULL ,
"PostalCode" nvarchar (10) NULL ,
"Country" nvarchar (15) NULL ,
"HomePhone" nvarchar (24) NULL ,
"Extension" nvarchar (4) NULL ,
"Photo" "image" NULL ,
"Notes" "ntext" NULL ,
"ReportsTo" "int" NULL ,
"PhotoPath" nvarchar (255) NULL ,
CONSTRAINT "PK_Employees" PRIMARY KEY CLUSTERED
(
"EmployeeID"
),
CONSTRAINT "FK_Employees_Employees" FOREIGN KEY
(
"ReportsTo"
) REFERENCES "dbo"."Employees" (
"EmployeeID"
),
CONSTRAINT "CK_Birthdate" CHECK (BirthDate < getdate())
)
GO
CREATE INDEX "LastName" ON "dbo"."Employees"("LastName")
GO
CREATE INDEX "PostalCode" ON "dbo"."Employees"("PostalCode")
GO
set quoted_identifier on
go
set identity_insert "Employees" on
go
ALTER TABLE "Employees" NOCHECK CONSTRAINT ALL
go
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(1,'Davolio','Nancy','Sales Representative','Ms.','12/08/1948','05/01/1992','507 - 20th Ave. E.
Apt. 2A','Seattle','WA','98122','USA','(206) 555-9857','5467',null,'Education includes a BA in psychology from Colorado State University in 1970. She also completed "The Art of the Cold Call." Nancy is a member of Toastmasters International.',2,'http://accweb/emmployees/davolio.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(2,'Fuller','Andrew','Vice President, Sales','Dr.','02/19/1952','08/14/1992','908 W. Capital Way','Tacoma','WA','98401','USA','(206) 555-9482','3457',null,'Andrew received his BTS commercial in 1974 and a Ph.D. in international marketing from the University of Dallas in 1981. He is fluent in French and Italian and reads German. He joined the company as a sales representative, was promoted to sales manager in January 1992 and to vice president of sales in March 1993. Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.',NULL,'http://accweb/emmployees/fuller.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(3,'Leverling','Janet','Sales Representative','Ms.','08/30/1963','04/01/1992','722 Moss Bay Blvd.','Kirkland','WA','98033','USA','(206) 555-3412','3355',null,'Janet has a BS degree in chemistry from Boston College (1984). She has also completed a certificate program in food retailing management. Janet was hired as a sales associate in 1991 and promoted to sales representative in February 1992.',2,'http://accweb/emmployees/leverling.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(4,'Peacock','Margaret','Sales Representative','Mrs.','09/19/1937','05/03/1993','4110 Old Redmond Rd.','Redmond','WA','98052','USA','(206) 555-8122','5176',null,'Margaret holds a BA in English literature from Concordia College (1958) and an MA from the American Institute of Culinary Arts (1966). She was assigned to the London office temporarily from July through November 1992.',2,'http://accweb/emmployees/peacock.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(5,'Buchanan','Steven','Sales Manager','Mr.','03/04/1955','10/17/1993','14 Garrett Hill','London',NULL,'SW1 8JR','UK','(71) 555-4848','3453',null,'Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1976. Upon joining the company as a sales representative in 1992, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London. He was promoted to sales manager in March 1993. Mr. Buchanan has completed the courses "Successful Telemarketing" and "International Sales Management." He is fluent in French.',2,'http://accweb/emmployees/buchanan.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(6,'Suyama','Michael','Sales Representative','Mr.','07/02/1963','10/17/1993','Coventry House
Miner Rd.','London',NULL,'EC2 7JR','UK','(71) 555-7773','428',null,'Michael is a graduate of Sussex University (MA, economics, 1983) and the University of California at Los Angeles (MBA, marketing, 1986). He has also taken the courses "Multi-Cultural Selling" and "Time Management for the Sales Professional." He is fluent in Japanese and can read and write French, Portuguese, and Spanish.',5,'http://accweb/emmployees/davolio.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(7,'King','Robert','Sales Representative','Mr.','05/29/1960','01/02/1994','Edgeham Hollow
Winchester Way','London',NULL,'RG1 9SP','UK','(71) 555-5598','465',null,'Robert King served in the Peace Corps and traveled extensively before completing his degree in English at the University of Michigan in 1992, the year he joined the company. After completing a course entitled "Selling in Europe," he was transferred to the London office in March 1993.',5,'http://accweb/emmployees/davolio.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(8,'Callahan','Laura','Inside Sales Coordinator','Ms.','01/09/1958','03/05/1994','4726 - 11th Ave. N.E.','Seattle','WA','98105','USA','(206) 555-1189','2344',null,'Laura received a BA in psychology from the University of Washington. She has also completed a course in business French. She reads and writes French.',2,'http://accweb/emmployees/davolio.bmp')
GO
INSERT "Employees"("EmployeeID","LastName","FirstName","Title","TitleOfCourtesy","BirthDate","HireDate","Address","City","Region","PostalCode","Country","HomePhone","Extension","Photo","Notes","ReportsTo","PhotoPath") VALUES(9,'Dodsworth','Anne','Sales Representative','Ms.','01/27/1966','11/15/1994','7 Houndstooth Rd.','London',NULL,'WG2 7LT','UK','(71) 555-4444','452',null,'Anne has a BA degree in English from St. Lawrence College. She is fluent in French and German.',5,'http://accweb/emmployees/davolio.bmp')
go
set identity_insert "Employees" off
go
ALTER TABLE "Employees" CHECK CONSTRAINT ALL
go
set quoted_identifier on
go
Select * from "Employees"
It's probably helpful to analyse your match rule a little, if we break it down we can see that the non-negotiable condition for a match is that either the FirstName OR the LastName matches. So let's build a query where we join only those rows from the employee table:
...
FROM #holder As h
JOIN Employee As e
ON h.FirstName = e.FirstName
OR h.LastName = e.LastName
...
Now that we're only looking at rows which meet the minimum criteria, we can assess the others. Basically your rule says that if either FirstName or LastName match, then we need a minimum of three of the following (let's assume that we matched FirstName):
Match LastName
Match City AND State, OR PostalCode
Match HomePhone
Match Extension
You present different rules depending if both FirstName and LastName match, but as long as you have one of those two then it so happens that the rules are mathematically equivalent from the perspective that I'm taking.
So we can take our potential match rows and just count how many of those matching attributes there are, and filter out rows where there aren't enough.
Select h.holderidentitykey, e.*
From #holder As h
Join Employees As e
On h.FirstName = e.FirstName
Or h.lastname = e.LastName
Where iif(h.firstname = e.firstname, 1, 0) +
iif(h.lastname = e.LastName, 1, 0) +
iif((h.city = e.City AND h.stateabbr = e.Region) OR h.zip = e.PostalCode, 1, 0) +
iif(h.homephone = e.HomePhone, 1, 0) +
iif(h.extension = e.Extension, 1, 0) >= 4;
Please note that this approach may not scale well if you have large tables (1M+) and want to match often, but if/when those situations occur then you could look at refactoring.

SQL Server table design to define WHERE condition

I have an existing Stored procedure which has lots of hard-coding with IF conditions. The procedure checks the values of following input fields and displays relevant message: The fields are:
• BrandId
• ProductId
• SchemeId
• RegionId
The existing Message table:
MsgId MsgText
1 AAAA
2 BBBB
3 CCCC
4 MMMM
Existing stored proc. pseudo code:
IF(BrandId in (5,10))
IF(#ProductId in (5))
SELECT ‘BBBB’ as MsgText
END IF
END IF
IF(SchemeId in (1,5,10))
SELECT ‘AAAA’ as MsgText
IF(SchemeId =2 AND #RegionId=4)
SELECT ‘BBBB’ as MsgText
IF (#RegionId=6)
SELECT ‘MMMM’ as MsgText
In order to remove hard-coding and re-writing the procedure cleanly from scratch, I want to design new tables which will store "MsgId"s against a BrandId/ProdId/PlanId/SchemeId value or against a combination of these fields (e.g SchemeId =2 AND RegionId=4).With this kind of design I can directly fetch the relevant MsgId against a specific field or combination of fields.
Could anybody suggest table designs to meet the requirement?
Based on your responses to the comments, this might work out.
create table dbo.[Messages] (
MessageId int not null
, MessageText nvarchar(1024) not null
, constraint pk_Messages primary key clustered (MessageId)
);
insert into dbo.[Messages] (MessageId,MessageText) values
(1,'AAAA')
, (2,'BBBB')
, (13,'MMMM');
create table dbo.Messages_BrandProduct (
BrandId int not null
, ProductId int not null
, MessageId int not null
, constraint pk_Messages_BrandProduct primary key clustered
(BrandId, ProductId, MessageId)
);
insert into dbo.Messages_BrandProduct (BrandId, ProductId, MessageId) values
(5,5,2)
,(10,5,2);
create table dbo.Messages_SchemeRegion (
SchemeId int not null
, RegionId int not null
, MessageId int not null
, constraint pk_Messages_SchemeRegion primary key clustered
(SchemeId, RegionId, MessageId)
);
insert into dbo.Messages_SchemeRegion (SchemeId, RegionId, MessageId)
select SchemeId = 1, RegionId , MessageId = 1 from dbo.Regions
union all
select SchemeId = 5, RegionId , MessageId = 1 from dbo.Regions
union all
select SchemeId = 10, RegionId , MessageId = 1 from dbo.Regions
union all
select SchemeId = 2, RegionId = 4, MessageId = 2
union all
select SchemeId , RegionId = 6, MessageId = 13 from dbo.Schemes;
In your procedure you could pull the messages like this:
select MessageId
from dbo.Messages_BrandProduct mbp
inner join dbo.[Messages] m on mbp.MessageId=m.MessageId
where mbp.BrandId = #BrandId and mbp.ProductId = #ProductId
union -- union all if you don't need to deduplicate messages
select MessageId
from dbo.Messages_SchemeRegion msr
inner join dbo.[Messages] m on msr.MessageId=m.MessageId
where msr.SchemeId = #SchemeId and msr.RegionId = #RegionId;
This should do it.
CREATE TABLE [dbo].[IDs](
[BrandID] [int] NOT NULL,
[ProductID] [int] NOT NULL,
[SchemeID] [int] NOT NULL,
[RegionID] [int] NOT NULL,
[MsgID] [int] NOT NULL
)
You can adjust the table and column names as needed. Cheers.

How to replace SELECT statement inside IF statement for it to work [duplicate]

This question already has answers here:
Oracle: how to INSERT if a row doesn't exist
(9 answers)
Closed 9 years ago.
I have a simple question - for examples sake let's have the table
CITY(ID,Name).
An idea would be that when I want to add new city I first make sure it's not already in the table CITY.
Code example would be:
IF cityName NOT IN (SELECT name FROM city) THEN
INSERT INTO City(ID, NAME) VALUES(100, cityName);
ELSE
Raise namingError;
END IF;
However I can't have that subquery inside if statement so what should I replace it with? Any kind of list or variable or trick that I could use?
IF NOT EXISTS(SELECT 1 FROM CITY WHERE NAME = <CITYNAME>)
INSERT INTO City(ID, NAME) VALUES(100, cityName);
OR
INSERT INTO City
SELECT 100,'cityName'
FROM dual
WHERE NOT EXISTS (SELECT 1
FROM CITY
WHERE name = cityname
)
I read the second query here
I don't have a database to try this out, but this should work
You could use a merge command to perform the insert into the table. While the merge command is used to perform an insert if the data is not present or an update if the data is present in this case since you just have two fields it will just preform the insert for you.
This is useful if you want to take data from one or more tables and combine them into one.
MERGE INTO city c
USING (SELECT * FROM city_import ) h
ON (c.id = h.id and c.city = h.city)
WHEN MATCHED THEN
WHEN NOT MATCHED THEN
INSERT (id, city)
VALUES (h.id, h.city);
http://www.oracle-base.com/articles/9i/merge-statement.php
If it was me I'd probably do something like
DECLARE
rowCity CITY%ROWTYPE;
BEGIN
SELECT * INTO rowCity FROM CITY c WHERE c.NAME = cityName;
-- If we get here it means the city already exists; thus, we raise an exception
RAISE namingError;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- cityName not found in CITY; therefore we insert the necessary row
INSERT INTO City(ID, NAME) VALUES(100, cityName);
END;
Share and enjoy.
Two options:
One using INSERT INTO ... SELECT with a LEFT OUTER JOIN; and
The other using MERGE
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE city (
ID NUMBER(2) PRIMARY KEY,
NAME VARCHAR2(20)
);
INSERT INTO city
SELECT 1, 'City Name' FROM DUAL;
CREATE TABLE city_errors (
ID NUMBER(2),
NAME VARCHAR2(20),
TS TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ERROR VARCHAR2(20)
);
Query 1:
DECLARE
city_id CITY.ID%TYPE := 2;
city_name CITY.NAME%TYPE := 'City Name';
namingError EXCEPTION;
PRAGMA EXCEPTION_INIT( namingError, -20001 );
BEGIN
INSERT INTO city ( id, name )
SELECT city_id,
city_name
FROM DUAL d
LEFT OUTER JOIN
city c
ON ( c.name = city_name )
WHERE c.id IS NULL;
IF SQL%ROWCOUNT = 0 THEN
RAISE namingError;
END IF;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
-- Do something when duplicate ID found.
INSERT INTO city_errors ( ID, NAME, ERROR ) VALUES ( city_id, city_name, 'Duplicate ID' );
WHEN namingError THEN
-- Do something when duplicate Name found.
INSERT INTO city_errors ( ID, NAME, ERROR ) VALUES ( city_id, city_name, 'Duplicate Name' );
END;
Results:
Query 2:
DECLARE
city_id CITY.ID%TYPE := 3;
city_name CITY.NAME%TYPE := 'City Name';
namingError EXCEPTION;
PRAGMA EXCEPTION_INIT( namingError, -20001 );
BEGIN
MERGE INTO city c
USING ( SELECT city_id AS id,
city_name AS name
FROM DUAL ) d
ON ( c.Name = d.Name )
WHEN NOT MATCHED THEN
INSERT VALUES ( d.id, d.name );
IF SQL%ROWCOUNT = 0 THEN
RAISE namingError;
END IF;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
-- Do something when duplicate ID found.
INSERT INTO city_errors ( ID, NAME, ERROR ) VALUES ( city_id, city_name, 'Duplicate ID' );
WHEN namingError THEN
-- Do something when duplicate Name found.
INSERT INTO city_errors ( ID, NAME, ERROR ) VALUES ( city_id, city_name, 'Duplicate Name' );
END;
Results:
Query 3:
SELECT * FROM City
Results:
| ID | NAME |
|----|-----------|
| 1 | City Name |
Query 4:
SELECT * FROM City_Errors
Results:
| ID | NAME | TS | ERROR |
|----|-----------|--------------------------------|----------------|
| 2 | City Name | January, 02 2014 20:01:49+0000 | Duplicate Name |
| 3 | City Name | January, 02 2014 20:01:49+0000 | Duplicate Name |

Resources