Modifying a SQL table to insert data from an existing row into the previous row - sql

I have a SQL table called RawData with the following six columns (all type VARCHAR):
Name StreetAddress State Phone Website Email
I import new data from a CSV file into this table on a regular basis and 99% of it is formatted correctly. For 1% of the data, for reasons that I understand but are not important for this question, the data is imported such that all of the first five columns (Name, StreetAddress, State, Phone, Website) have data that is formatted correctly but the sixth column Email is blank. Furthermore, the email is imported into its own row immediately below this "problem" row but the email is placed in the Name column. These situations are readily identified begins the email address is always inserted in the Name column with the mailto: prefix .
What I would like to do is devise a query to take the incorrectly placed email address from the Name, strip the mailto: prefix and then place it into the Email column in the previous row. I would then like to delete the row with the 'mailto:' email in the `Name' column.
I've done a bit of research and believe that I need to use a cursor to copy the data from the row below the correct row and insert it into the Email column but having never used cursors before, I am struggling to come up with anything. Any help would be appreciated.
Edit: For the purposes of brevity, I omitted that the table does contain an identity column ID.

In SQL Server, there is no concept of "previous" row. You are going to need to add an identity column to the table so you can identify these situations. Fortunately, you can insert your data into a view, so the identity is automatically incremented in the load order.
Once you have the id, you can use an update:
update nd
set nd.email = stuff(ndnext.name, 1, 7, '')
from newdata nd join
newdata ndnext
on nd.id = ndnext.id - 1
where ndnext.name like 'mailto:%';
Once you have verified that this is correct, you probably want to do:
delete nd from nd
where nd.name like 'mailto:%';

Related

Is it OK to have separate column in Audit table to store column name to reflect what changes were made

Is it a good practice to store column name to represent what were the changes made in a data in parent table which led to trigger the audit.
Ex :-
create table employee
(
emp_id character varying(10),
fname character varying(30),
lname character varying(30),
tel_no character varying(15)
);
create table aud_employee
(
emp_id character varying(10),
fname character varying(30),
lname character varying(30),
tel_no character varying(15)
aud_col_changed character varying(100)
);
--
insert into employee values('215','Mark','Cooper','222-458-254');
This will also result to insert the record in an audit table through trigger and will have null value in aud_col_changed column.
Now when I update the same record :-
update employee set tel_no='255-458-254' where emp_id='215';
So, audit would also be created for this update made and audit table should now consist another record and would consist value 'tel_no' in aud_col_changed column.
If there are multiple columns changed at a time, it would be separated by comma in same field.
If this is the right approach, could you please describe the ways of achieving it?
Please note that the table on which I am trying to implement this approach has around 18 columns out of whih 6-7 columns are JSON.
Your method is likely to be fine -- you should specify what you want to do with the audit table.
Personally, I would rather have a table where the audit table was one of the following:
One row per column changed, with the old value and the new value.
One row per row changed, with all the columns appearing twice, once for the old value and once for the new value.
In other words, I usually want to see both the old and new values together.
The first method is tricky when dealing with columns that have different types. The second is tricky when you want to modify the structure of the table.
I did some more research and I found that if we want to store column name then that data needs to be updated through function. In function we need to check each value passed with NOT NULL. If it appears to be not null then we need to hard code the column name and assign it to the variable. If more values are found which are NOT NULL, then that hard coded column name needs to be appended to main variable until we check all the values passed in function with NOT NULL.
This will definitely degrade performance of DB and making it run after every update is obviously not preferable.
Hence, I will not prefer using audit_col_changed column.

Updating a table column using LIKE in WHERE

I have a table(ENTITY) that needs to be updated based on an ID(FUNNCODE) but the ID(FUNNCODE) is linked between two other tables(from JOINT then to POSITION)
and is independent of where the data is at(table NEORSD). The only parameter I can bind is the position name between the NEORSD table and POSITION table. When I place my LIKE statement into the where clause I get an error in return. If anyone can point me in the right direction it would be greatly appreciated!
Tables:
NEORSD: Contains the range information and 'position name(= Tag_No)'
ENTITY: Needs to update and accept the range information (Holds FUNCCODE)
JOINT: Holds FUNCCODE(named POSFUNCCODE) and corresponding POSCODE
POSITION: Contains POSCODE and 'position name(=POSID)'
UPDATE ENTITY
SET
RANGE0 = (
SELECT RANGE0
FROM NEORSD_1199
WHERE Tag_No like ('%PIT%'))
WHERE
FUNCCODE = (
SELECT POSFUNCCODE
FROM JOINT
WHERE POSCODE = (
SELECT POSCODE
FROM POSITION
WHERE POSID like ('%PIT%'))
If NEORSD_1199 has more than one row with a tag_no like '%PIT%', which NEORSD_1199.RANGE0 value should it use to update ENTITY.RANGE0?
This is the db engine's problem with your SQL.
To better understand, read the SQL backwards:
First you're getting a list of every Position Code from the POSITION table where the Position ID is like '%PIT%'. That might be one code, and it might be one hundred codes.
Then you're getting every Position Function Code from the JOINT table where the Position Code is in the list of Position Codes you just gathered. Again, could be one, could be a hundred.
Then you're getting a list of all values of RANGE0 from the NEORSD1199 table where Tag_No is like '%PIT%'. Again, this could be one value, or a list of one hundred.
Then, you're getting every row from the ENTITY table where the Function Code is in the list of Position Function Codes you gathered from the JOINT table (step 2 above), and you're updating RANGE0 in each of these rows to the value you captured in step 3.
The problem is that the 'value' returned in step 3 could be a list of values. If
NEORSD1199 has four rows where tag number is like '%PIT%'
(e.g. PIT01,PIT02,PIT03,APIT00), and each of those rows has a different
RANGE0 (e.g. 1,2,3,99), then which of those four values should the DB engine use to update RANGE0 in the rows in the ENTITY table?
Thank you to #SQLCliff for the questions that help to find the solution. I created an ID column inside my NEORSD table, created a temporary table holding the link between FUNCCODE and the ranges in NEORSD. Then I updated ENTITY using a join on. I can insert the where clause at the end of the temporary table for filtering if needed. Since it is a mass update I no longer require a where clause. My brain just likes making things more complicated than they need to be XD
with t as(
select f.funccode as funccode ,n.range0, n.range100
from func as f
join NEORSD_1199_With_Ranges_Updated as n on n.id = f.poscode or n.id =f.devcode
/* WHERE nessecrary ;P*/)
update entity
set
range0 = t.range0,
range100 = t.range100
from entity as e
join t on e.funccode = t.funccode

Get values based on newly inserted value using SQL

I want to make filtration on a column after selecting a specific value of another column in the same table, I tried to use #... special character followed by the column's name to get the address of this value.
My SQL statement is like the following :
SELECT ATTRIBUTE FROM TABLE WHERE FIELD = '#FIELDNAME';
If I used a specific value instead of #FIELDNAME, it will work properly but it will be static but I need it to be dynamic based on the selected value.
Create another table which will have the list of values that are in the FIELDNAME and give each record a unique id ,then retrieve the value depending on what you have selected by the name of the new table's field preceded by '#...'
I don't know if that what are you looking for, please let me know.
If no triggers are allowed, do you have any date/time column in the table? Is it possible to have that extra column anyway to see the time of a newly inserted row?
You may have to check the lastest row entered, save its field value into a variable. Then do the select based on the variable value.
Based on the vague last row id you could try the following (it's not pretty). But again, if you have date/time that's more accurate.
select attribute from table
where field = (select field from table
where rowid =(select max(rowid) from table))
;
upate
Do you have the priviledge to set up your insert command as below:
insert into table (id, col1, col2,...) values (1,'something', 'something',...)
returning id into variable; -- you may either save field or id depending on your table
Then you may use this variable to select the records you want.

SQL: I need to take two fields I get as a result of a SELECT COUNT statement and populate a temp table with them

So I have a table which has a bunch of information and a bunch of records. But there will be one field in particular I care about, in this case #BegAttField# where only a subset of records have it populated. Many of them have the same value as one another as well.
What I need to do is get a count (minus 1) of all duplicates, then populate the first record in the bunch with that count value in a new field. I have another field I call BegProd that will match #BegAttField# for each "first" record.
I'm just stuck as to how to make this happen. I may have been on the right path, but who knows. The SELECT statement gets me two fields and as many records as their are unique #BegAttField#'s. But once I have them, I haven't been able to work with them.
Here's my whole set of code, trying to use a temporary table and SELECT INTO to try and populate it. (Note: the fields with # around the names are variables for this 3rd party app)
CREATE TABLE #temp (AttCount int, BegProd varchar(255))
SELECT COUNT(d.[#BegAttField#])-1 AS AttCount, d.[#BegAttField#] AS BegProd
INTO [#temp] FROM [Document] d
WHERE d.[#BegAttField#] IS NOT NULL GROUP BY [#BegAttField#]
UPDATE [Document] d SET d.[#NumAttach#] =
SELECT t.[AttCount] FROM [#temp] t INNER JOIN [Document] d1
WHERE t.[BegProd] = d1.[#BegAttField#]
DROP TABLE #temp
Unfortunately I'm running this script through a 3rd party database application that uses SQL as its back-end. So the errors I get are simply: "There is already an object named '#temp' in the database. Incorrect syntax near the keyword 'WHERE'. "
Comment out the CREATE TABLE statement. The SELECT INTO creates that #temp table.

sql - retain calculated result in calculated field

certain fields in our database contain calculated functions e.g.
select lastname + ', ' + firstname as fullname from contact where contact.id =$contact$
when viewing the field the correct data is shown (i assume this is because when you open the record, the calculation is executed). however, the data is not 'stored' to the field, and therefore is null until the record is opened. is it possible to 'store' the result to the field, making it possible to search the data?
many thanks
james
EDIT
it is not possible for me to create computed_columns using our software.
the above field is a text feild where either 1) a user can manual type in the required data or 2) the database can generate the answer for you (but only whilst you are looking at the record). i know that if I run the following:
Select * from contact where contact.id =$contact$ for xml auto
i only get lastname, firstname - so i know that the fullname field does not retain its information.
If you are using computed columns in sql server, the column is already searchable regardless of whether the calculation result is stored or not. However, if you would like to make it so that the calculation is not run each time you read the row, you can change that under row properties in your Modify Table GUI.
Use the PERSISTED key word when you create the column
From BOL:
PERSISTED
Specifies that the SQL Server Database Engine will physically store the computed values in the table, and update the values when any other columns on which the computed column depends are updated. Marking a computed column as PERSISTED lets you create an index on a computed column that is deterministic, but not precise. For more information, see Creating Indexes on Computed Columns. Any computed columns that are used as partitioning columns of a partitioned table must be explicitly marked PERSISTED. computed_column_expression must be deterministic when PERSISTED is specified.
This isn't the way computed columns work in SQL Server, so I suspect this is something your client application is doing. How are you looking at the data when the value is computed correctly? Does it work when you view the data in SSMS?
Take a look at http://msdn.microsoft.com/en-us/library/ms191250(v=SQL.90).aspx to see how to create computed columns properly.
eg.
create table TestTable
(a int,
b int,
c as a + b)
insert into TestTable (a,b)
values (1,2)
select * from TestTable
where c = 3
This query is based on the computed column and it returns the row that's been inserted.
You need to use the PERSISTED option on a column when you use CREATE TABLE e.g.
CREATE TABLE test (col_a INT, col_b INT, col_c AS col_A * col_B PERSISTED)