variables in complex sql queury/rule - sql

I want to insert values into a view, which is over multiple tables. I use Postgresql.
My solution is to write a rule which inserts all the data into the right table and adds the foreign keys into the rows.
My question is: Can I somehow declare variables into the rule for recurring select-statements?
The code for the rule is:
create rule insert_new_user as on insert to "collHBRS".loginview do instead(
-- add email_address to email table
insert into "collHBRS".email(email_addr) values (new.login_name);
-- add new empty profile to profile table
insert into "collHBRS".profile(profile_email_fk, profile_address_fk, profile_student_fk, profile_company_fk)
VALUES (
(select email_id from "collHBRS".email where email_addr = new.login_name), -- get email_fk
null,null,null);
-- create new login
insert into "collHBRS".login(login_email_fk, login_password, login_salt, last_login, login_profile_fk)
values (
(select email_id from "collHBRS".email where email_addr = new.login_name), -- get email_fk
new.login_password,new.login_salt,now(),
(select profile_id from "collHBRS".profile where profile_email_fk =
(select email_id from "collHBRS".email where email_addr = new.login_name) -- get profile_fk with email_fk
)
)
);
I repeat the select-statement to get the primary key from my new email entry like 2 times.
(select email_id from "collHBRS".email where email_addr = new.login_name)
I tried it, with DECLARE and WITH AS.
The rule works, it is just not pretty.
Thank you

Related

While updating table1, how do I INSERT to table2 for every change in table 1?

I have a MEMBER table and NOTIFICATION table. On client side, I list all of the records in MEMBER table and there is a points column and this is shown as text input. So after I change the values for some members, I can click save button and this will update the records in my MEMBER table that's all right,
But the thing I want to accomplish is for every record whose points value has changed I want to INSERT a record in my notifications table.
I couldn't think of anything, how can I approach to this problem?
For notifications I made 3 tables by following the article in here
Use the output clause instead of trigger, they are bad.
You need the condition "where data_old <> data_new" case if you updated a column with the same value, SQL Server marked it as changed, even if the value hasn't changed
create table #example (id int identity(1,1) not null, data nvarchar(max));
insert into #example (data) values ('value 1'),('value 2'), ('value 3');
create table #audit (id int, data_old nvarchar(max), data_new nvarchar(max), [When] datetime not null default (getdate()));
insert into #audit (id, data_old, data_new)
select id, data_old, data_new
from (
update #example
set data = 'value changed'
output inserted.id, deleted.data as data_old, inserted.data as data_new
where id = 2
)changed (id, data_old, data_new)
where data_old <> data_new
select * from #audit
will result with this in #audit :
You have described what a trigger does.
create trigger trig_member_insert on members after update
as
begin
insert into notifications ( . . . )
select . . ., i.points as new_points u.points as old_points -- what you want to insert
from inserted i join
updated u
on i.member_id = u.member_id
where u.points <> i.points
end;
Storing something called "points" as a string seems like a very poor choice. It sounds like a number.

Database inner join update

I am trying to update a table column from a table column in another table and am using the following code - it generates the error below.
Any ideas?
UPDATE URLRecord
  SET URLRecord.Slug = aaNewURLSlugss.NewSlugName
FROM URLRecord
INNER JOIN aaNewURLSlugs ON URLRecord.Slug = aaNewURLSlugss.OldSlugName
Error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ','.
SQL Server doesn't like the qualified column name in SET. Does this work?
UPDATE r
SET Slug = n.NewSlugName
FROM URLRecord r inner join
aaNewURLSlugs n
ON r.Slug = n.OldSlugName;
The error message would be different, though, from what you are getting. This would be an additional error.
Here is a working solution that uses a temporary table. It may not be ideal and I've included some drop statements, so don't run this on your production machine.
-- Build our test tables
CREATE TABLE [URLRecord]
(
[Id] INTEGER IDENTITY PRIMARY KEY,
[Slug] CHARACTER VARYING(255) NOT NULL
)
GO
CREATE TABLE [NewSlugs]
(
[Id] INTEGER IDENTITY PRIMARY KEY,
[NewSlugName] CHARACTER VARYING(255) NULL,
[OldSlugName] CHARACTER VARYING(255) NULL
)
GO
-- Insert test data
INSERT INTO [URLRecord] VALUES ('Original Name');
INSERT INTO [NewSlugs] VALUES ('New Name', 'Original Name');
-- Populate work table with the records we want to modify
SELECT [URLRecord].[Id], [NewSlugs].[NewSlugName] INTO #SlugWork
FROM [URLRecord]
INNER JOIN [NewSlugs] ON [URLRecord].[Slug] = [NewSlugs].[OldSlugName]
-- We're just echoing here
SELECT * FROM #SlugWork
-- Pull everything from our temporary table and update modified records
UPDATE [URLRecord]
SET [URLRecord].[Slug] = [T].[NewSlugName]
FROM #SlugWork AS [T]
WHERE [T].[Id] = [URLRecord].[Id]
-- Proving it's updated
SELECT * FROM [URLRecord]
-- Drop our example stuff, for rerunnability
DROP TABLE #SlugWork
DROP TABLE [NewSlugs]
DROP TABLE [URLRecord]
Try using Aliases
UPDATE A
SET A.Slug = B.NewSlugName
FROM URLRecord AS A
INNER JOIN aaNewURLSlugs B
ON A.Slug = B.OldSlugName
Try to use embedded sql like this:
UPDATE URLRecord
SET Slug = (
SELECT NewSlugName
FROM aaNewURLSlugs
WHERE URLRecord.Slug = aaNewURLSlugs.OldSlugName )
WHERE Slug IN (SELECT OldSlugName FROM aaNewURLSlugs)

SQL - Dynamic Lookup with Regex

I would like to determine the ownership of a folder. Therefore every folder has a constant naming convention, which is stored in the table OWNER(ident_string).
Using the ident_string I want to determine the owner_id and write it (update) into table FOLDER(owner_id).
I have following tables in Postgresql:
create table owner(
owner_id serial PRIMARY KEY,
owner_name varchar(100),
ident_string varchar(100));
create table folder(
folder_id serial PRIMARY KEY,
folder_name varchar(80),
folder_path varchar(800),
owner_id integer references owner(owner_id));
insert into owner (owner_name, ident_string) values ('Jonny English','b-jonny');
insert into owner (owner_name, ident_string) values ('Hanna Babara','b-hanna');
insert into owner (owner_name, ident_string) values ('Mary Marmelade','b-mary');
insert into folder (folder_name,folder_path) values ('b-jonny-20130101','/archive/backup/b-jonny-20130101');
insert into folder (folder_name,folder_path) values ('b-jonny-20130103','/archive/backup/b-jonny-20130103');
insert into folder (folder_name,folder_path) values ('b-hanna-20140101','/archive/backup/b-jonny-20140101');
insert into folder (folder_name,folder_path) values ('b-mary-20120303','/archive/backup/b-mary-20120303');
I think the only possiblity to do so is via PL/pgSQL:
iterate for folder_name in FOLDER over every row in OWNER
check for every ident_string to lookup the owner_id.
Could somebody help me out?
Maybe something similar to the following?
update folder set folder.owner_id = owner.owner_id from folder join owner on folder_name like owner.ident_string + '%'
(like is the method for regexs in sql)
Try this:
update folder as f
set owner_id = o.owner_id
from owner as o
where o.ident_string = left(f.folder_name,length(o.ident_string));
-g
You could create table folder in one sentence:
insert into folder (folder_name,folder_path,owner_id)
with tmp (folder_name,folder_path) as
(
select 'b-jonny-20130101','/archive/backup/b-jonny-20130101' union all
select 'b-jonny-20130103','/archive/backup/b-jonny-20130103' union all
select 'b-hanna-20140101','/archive/backup/b-jonny-20140101' union all
select 'b-mary-20120303','/archive/backup/b-mary-20120303'
)
select folder_name,folder_path,o.owner_id
from tmp
join owner o
on tmp.folder_name ~ o.ident_string;
select * from owner;
Use a regular expression (~), it's more powerful.
See SQL FIDDLE DEMO

Updating both rows and columns in oracle

Can rows be upadted along with the colums for a table.
I had a table where amount was to be updated for single member for 3 different years
I used the following query
update ahd
set amount1=(select a.amnt1
from ahd inner join ahdtmp a on ahd.member_key=a.member_key
where ahd.date1=a.date1
and a.status='FALSE'
and a.member_key in (select distinct member_key
from ahd))
When I execute this
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row
The temporary table is ahdtmp
create table ahdtmp(
member_key number(10),
date1 date,
amnt1 number(10,2),
amnt2 number(10,2),
date_amend date,
Status varchar2(10));
Please suggest on this?
What could have gone wrong..
Possibly what you want is:
update ahd
set amount1=(select a.amnt1
from ahdtmp a
where ahd.member_key=a.member_key and
ahd.date1 =a.date1
and a.status='FALSE')
where member_key = 'some particlar member ey'
Maybe the following script will be useful, is a generic code (its only an example):
CREATE TABLE SOURCE(
s_key int,
s_name varchar2(100));
CREATE TABLE TARGET(
t_key int,
t_name varchar2(100));
INSERT INTO SOURCE VALUES(1,'A');
INSERT INTO SOURCE VALUES(2,'B');
INSERT INTO SOURCE VALUES(3,'C');
INSERT INTO SOURCE VALUES(4,'D');
INSERT INTO TARGET VALUES(1,'Z');
INSERT INTO TARGET VALUES(2,'Z');
INSERT INTO TARGET VALUES(3,'Z');
INSERT INTO TARGET VALUES(4,'Z');
/*HERE THE CODE*/
MERGE
INTO target
USING (
SELECT s.s_name,s.s_key
FROM source s
)
ON (t_key = s_key)
WHEN MATCHED THEN
UPDATE
SET t_name = s_name;
Here the link to try this example (it works fine) sql fiddle.
I not sure but your query would be something like this:
MERGE
INTO ahd
USING (
SELECT a.amnt1
FROM ahdtmp a
)
ON (ahd.member_key=a.member_key)
WHEN MATCHED THEN
UPDATE
SET amount1 = amnt1
WHERE ahd.status='FALSE'
AND ahd.member_key IN (SELECT DISTINCT member_key FROM ahd);
Issue here is sub query returns multiple values. You have to filter it to return single record.
update ahd
set amount1=(select a.amnt1
from ahd inner join ahdtmp a on ahd.member_key=a.member_key
where ahd.date1=a.date1
and a.status='FALSE'
and a.member_key ='user_specific_key')

Solutions for tracking how many times certain parameters are used in a stored procedure SQL Server 2008

In my database have tables with structures similar to:
create table ItemNameSearches
(ItemName varchar(50) not null,timesSearched int not null,
primary key(ItemName))
and
create table ItemList
(ItemName varchar(50),
primary key (ItemName))
My idea is to have people enter in through a webform a comma-separated list of values so that they can get information about certain items. The table ItemList contains information about the item for which they searched (although the table structure doesn't reflect that in this example). If, however, the item searched for doesn't appear in the ItemList table, I would like for that ItemName to be inserted into the ItemNameSearches so I could have a better idea of what people are searching for.
Scenario 1: an item is searched for the first time and a new row is inserted into the ItemNameSearches table. I'm pretty sure this is an area for triggers, but I'm not familiar with using them so I wrote the following stored procedure:
create proc spSearchItemName
#itemName1 varchar(50)
,#itemName2 varchar(50) = null
,#itemName3 varchar(50) = null
,#itemName4 varchar(50) = null
as
begin
;with searchList
as
(select x.itemName
from (values (#itemName1)
,(#itemName2)
,(#itemName3)
,(#itemName4)
) as x(itemName)
where x.itemName is not null
--these are optional parameters just to give the user more flexibility
--on if they want to look at multiple items at once or not
)
insert into ItemNameSearches(itemName,timesSearched)
values
(
(select sl.itemName
from searchList as sl
left outer join ItemList as il
on il.itemName=sl.itemName
where il.itemName is null
--this subquery finds the items searched for that are not present in the
--itemlist table and sets timesSearched =1 for each
),1
)
end
This is well and good for the items that are searched for that do not appear in the ItemList table, but I would have to do something like the following procedure if they DID search for an item that was in the ItemList table
;with searchList
as
(select x.itemName
from (values ('item 1')
,('item 2')
,('item 3')
,('item 5')
) as x(itemName)
)
update ins
set timesSearched = timesSearched +1
from ItemNameSearches as ins
where itemName in
(select itemName from searchList)
So this will add 1 to the number of times an item was searched for if it exists in the ItemList table. Can someone provide a neat manner of how to solve these two different situations? Is this something that is a good candidate for triggers?
Thanks to #Gordon Linoff for providing the direction of using the merge statement, it ended up working perfectly for what I wanted to do. I ended up using the following sproc and it works fine.
alter proc spSearchDrugName
#drugName1 varchar(50)
,#drugName2 varchar(50) = null
,#drugName3 varchar(50) = null
,#drugName4 varchar(50) = null
,#drugName5 varchar(50) = null
as
begin
declare #searchList table(drugName varchar(50))
insert into #searchList
values (#drugName1)
,(#drugName2)
,(#drugName3)
,(#drugName4)
,(#drugName5)
merge DrugListSearches as d
using(select drugName from #searchList where drugName is not null) as s
on s.drugName = d.drugName
when matched then
update set d.timesSearched = d.timesSearched + 1
when not matched then
insert (drugname,timesSearched) values (s.drugName,1);
end