SQL query to SELECT and replace only one column value with out defining the other columns - sql

I have a need to do a select, but I need to replace one column's value out. The table has 25 columns, and I wanted to make this readable with out listing all columns to do the replacement of one column from another table. Here is what i did that does work,
SELECT *
INTO #temp_grouping
FROM [ae_p_phs_e]
WHERE [template_id] = '1010'
AND [status_code] = 'OPEN'
AND [shop] = 'SP-STEAM'
-- select row from the temp table for inserting
UPDATE #temp_grouping
SET
[description] = [source_data].[description]
FROM
[ae_a_asset_e] AS [source_data]
WHERE
[source_data].[asset_tag] = [#temp_grouping].[asset_tag]
AND [source_data].[multitenant_id] = [#temp_grouping].[multitenant_id]
SELECT *
FROM #temp_grouping
--drop the temp table
DROP TABLE #temp_grouping
But what are other ways to do this same thing?
SAMPLE
TABLE A
-------------------------------------------------
|col1 | col2 | description | .... | nthColumn|
-------------------------------------------------
TABLE B
-------------------------------------------------
|col1 | col2 | description | .... | nthColumn|
-------------------------------------------------
EXAMPLE Data return on the first TABLE A
1,2017-026221,001,BAD description,..... VERY LAST
1,2017-026221,002,BAD description,..... VERY LAST
1,2017-026221,003,BAD description,..... VERY LAST
1,2017-026221,004,BAD description,..... VERY LAST
1,2017-026221,005,BAD description,..... VERY LAST
EXAMPLE Data return on the first TABLE B
1,null,XX1,GOOD description,..... VERY LAST
1,null,XX2,GOOD description,..... VERY LAST
1,null,XX3,GOOD description,..... VERY LAST
1,null,XX4,GOOD description,..... VERY LAST
1,null,XX5,GOOD description,..... VERY LAST
EXAMPLE RETURN Data return, basically first TABLE A with one value on TABLE B
1,2017-026221,001,GOOD description,..... VERY LAST
1,2017-026221,002,GOOD description,..... VERY LAST
1,2017-026221,003,GOOD description,..... VERY LAST
1,2017-026221,004,GOOD description,..... VERY LAST
1,2017-026221,005,GOOD description,..... VERY LAST
Assume
Script Table As is a solution to auto fill the column, but is not going to fit for the need. The solution of the
question should not include the opposite of the question's request to
not list the columns as stated in the title.
A solution that requires GRANTS that will let you read the system table are not allowed in many cases.
Solution as of yet
It is starting to sound like the answer is there may not be another way to do what I did with out listing all columns out. If it doesn't turn out to be the case then I'll remove this section.

It is the only way to perform it using dynamic queries.
declare #query nvarchar(max) = ''
declare #temp_grouping nvarchar(max) = 'col1, col2, col3'
set #query = 'SELECT '+#temp_grouping+' FROM [ae_p_phs_e] where [template_id] = ''1010'''
print #query
exec sp_executesql #query

I am afraid your comment didn't really clarify what I'm trying to figure out, but let me go ahead and suggest a solution based on what I'm guessing you are trying to do. Actually, I have two solutions, based on two guesses:
You want to write a SELECT from a table with a lot of columns, so you want to avoid typing out all the column names for no other reason than that it would be a lot of typing. But you can't do a simple SELECT * because there is one column that you want to replace in the output with a column from another table.
Solution: Right click on the table in the SSMS Object Explorer pane, and choose Script Table As > SELECT To > New Query Window.
You will get a new query window with the SELECT query written out, with all the column names written out for you. No typing required. Then just modify that query with the JOIN you want, and find the column you want to replace in the SELECT list and replace it with the column from the JOINed table. This produces the SELECT query you want on an adhoc basis.
You have a more fluid situation where you don't necessarily know, for whatever reason, what the columns are going to be, so therefore you can't hard-code a column list, but you know that if a certain column appears, you want to replace it with a different one.
Solution: use a dynamic sql query, like the one in Rainman's answer. Instead of typing out the column list, like you mention in your comment to his answer, you can dynamically generate that list by querying the system tables to get all the columns belonging to the table you are interested in.

Related

Insert a column from output of a query into already populated postgresql database without adding new rows

I have a table named comments_live which has 4 fields and some 24000 entries. I want to add another field which is the output of a select query. The query is like this:
INSERT INTO comments_live SELECT SUBSTR(record,1, POSITION(' ' IN record)) AS project_id FROM comments_live;
What this query is doing is it's appending the result of the SELECT query to the table. I want the 'project_id' field to be appended to the existing 24000 rows. i.e. The above query should not add those extra rows to the table.
Any help would be appreciated.
PS: I tried adding a empty column 'project_id' to the table first and then executing the query, still I'm getting the same result.
I conclude from your code example that you want to add a column whose content is the substring from the column RECORD. If you succeeded in adding the empty column, then you just need code like the following:
update comments_live
set project_id=substr(record,1,[...])

Separating multiple values in one column in MS SQL

I have a field in an application that allows a user to select multiple values. When I query this field in the DB, if multiple values were selected the result gets displayed as one long word. There are no commas or space between the multiple selected values. Is there any way those values can be split by a comma?
Here’s my query:
SELECT HO.Value
FROM HAssessment ha
INNER JOIN HObservation HO
ON HO.AssessmentiD = ha.AssessmentID
AND HO.Patient_Oid = 2255231
WHERE Ho.FindingAbbr = 'A_R_CardHx'
------------------------------------------------
Result:
AnginaArrhythmiaCADCChest Pain
-------------------------
I would like to see:
Angina, Arrhythmia, CADC, Chest Pain
------------------------------------------
Help!
There's no easy solution to this.
The most expedient would be writing a string splitting function. From your sample data, it seems the values are all concatenated together without any separators. This means you'll have to come up with a list of all possible values (hopefully this is a query from some symptoms table...) and parse each one out from the string. This will be complex and painful.
A straightforward way to do this would be to test each valid symptom value to see whether it's contained within HObservation.Value, stuff all the found values together, and return the result. Note that this will perform very poorly.
Here's an example in TSQL. You'd be much better off doing this at the application layer, though, or better yet, normalizing your database (see below for more on that).
declare #symptoms table (symptom varchar(100))
insert into #symptoms (symptom)
values ('Angina'),('Arrhythmia'),('CADC'),('Chest Pain')
declare #value varchar(100)
set #value = 'AnginaArrhythmiaCADCChest Pain'
declare #result varchar(100)
select #result = stuff((
SELECT ', ' + s.symptom
FROM #symptoms s
WHERE patindex('%' + s.symptom + '%',#value) > 0
FOR XML PATH('')),1,1,'')
select #result
The real answer is to restructure your database. Put each distinct item found in HObservation.Value (this means Angina, Arrhythmia, etc. as separate rows) in to some other table if such a table doesn't exist already. I'll call this table Symptom. Then create a lookup table to link HObservation with Symptom. Then drop the HObservation.Value column entirely. Do the splitting work in the application level, and make multiple inserts in to the lookup table.
Example, based on sample data from your question:
HObservation
------------
ID Value
1 AnginaArrhythmiaCADC
Becomes:
HObservation
------------
ID
1
Symptom
-------
ID Value
1 Angina
2 Arrhythmia
3 CADC
HObservationSymptom
-------------------
ID HObservationID SymptomID
1 1 1
1 1 2
1 1 3
Note that if this is a production system (or you want to preserve the existing data for some other reason), you'll still have to write code to do the string splitting.

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.

change ID number to smooth out duplicates in a table

I have run into this problem that I'm trying to solve: Every day I import new records into a table that have an ID number.
Most of them are new (have never been seen in the system before) but some are coming in again. What I need to do is to append an alpha to the end of the ID number if the number is found in the archive, but only if the data in the row is different from the data in the archive, and this needs to be done sequentially, IE, if 12345 is seen a 2nd time with different data, I change it to 12345A, and if 12345 is seen again, and is again different, I need to change it to 12345B, etc.
Originally I tried using a where loop where it would put all the 'seen again' records in a temp table, and then assign A first time, then delete those, assign B to what's left, delete those, etc., till the temp table was empty, but that hasn't worked out.
Alternately, I've been thinking of trying subqueries as in:
update table
set IDNO= (select max idno from archive) plus 1
Any suggestions?
How about this as an idea? Mind you, this is basically pseudocode so adjust as you see fit.
With "src" as the table that all the data will ultimately be inserted into, and "TMP" as your temporary table.. and this is presuming that the ID column in TMP is a double.
do
update tmp set id = id + 0.01 where id in (select id from src);
until no_rows_changed;
alter table TMP change id into id varchar(255);
update TMP set id = concat(int(id), chr((id - int(id)) * 100 + 64);
insert into SRC select * from tmp;
What happens when you get to 12345Z?
Anyway, change the table structure slightly, here's the recipe:
Drop any indices on ID.
Split ID (apparently varchar) into ID_Num (long int) and ID_Alpha (varchar, not null). Make the default value for ID_Alpha an empty string ('').
So, 12345B (varchar) becomes 12345 (long int) and 'B' (varchar), etc.
Create a unique, ideally clustered, index on columns ID_Num and ID_Alpha.
Make this the primary key. Or, if you must, use an auto-incrementing integer as a pseudo primary key.
Now, when adding new data, finding duplicate ID number's is trivial and the last ID_Alpha can be obtained with a simple max() operation.
Resolving duplicate ID's should now be an easier task, using either a while loop or a cursor (if you must).
But, it should also be possible to avoid the "Row by agonizing row" (RBAR), and use a set-based approach. A few days of reading Jeff Moden articles, should give you ideas in that regard.
Here is my final solution:
update a
set IDnum=b.IDnum
from tempimiportable A inner join
(select * from archivetable
where IDnum in
(select max(IDnum) from archivetable
where IDnum in
(select IDnum from tempimporttable)
group by left(IDnum,7)
)
) b
on b.IDnum like a.IDnum + '%'
WHERE
*row from tempimport table = row from archive table*
to set incoming rows to the same IDnum as old rows, and then
update a
set patient_account_number = case
when len((select max(IDnum) from archive where left(IDnum,7) = left(a.IDnum,7)))= 7 then a.IDnum + 'A'
else left(a.IDnum,7) + char(ascii(right((select max(IDnum) from archive where left(IDnum,7) = left(a.IDnum,7)),1))+1)
end
from tempimporttable a
where not exists ( *select rows from archive table* )
I don't know if anyone wants to delve too far into this, but I appreciate contructive criticism...

SQL query select from table and group on other column

I'm phrasing the question title poorly as I'm not sure what to call what I'm trying to do but it really should be simple.
I've a link / join table with two ID columns. I want to run a check before saving new rows to the table.
The user can save attributes through a webpage but I need to check that the same combination doesn't exist before saving it. With one record it's easy as obviously you just check if that attributeId is already in the table, if it is don't allow them to save it again.
However, if the user chooses a combination of that attribute and another one then they should be allowed to save it.
Here's an image of what I mean:
So if a user now tried to save an attribute with ID of 1 it will stop them, but I need it to also stop them if they tried ID's of 1, 10 so long as both 1 and 10 had the same productAttributeId.
I'm confusing this in my explanation but I'm hoping the image will clarify what I need to do.
This should be simple so I presume I'm missing something.
If I understand the question properly, you want to prevent the combination of AttributeId and ProductAttributeId from being reused. If that's the case, simply make them a combined primary key, which is by nature UNIQUE.
If that's not feasible, create a stored procedure that runs a query against the join for instances of the AttributeId. If the query returns 0 instances, insert the row.
Here's some light code to present the idea (may need to be modified to work with your database):
SELECT COUNT(1) FROM MyJoinTable WHERE AttributeId = #RequestedID
IF ##ROWCOUNT = 0
BEGIN
INSERT INTO MyJoinTable ...
END
You can control your inserts via a stored procedure. My understanding is that
users can select a combination of Attributes, such as
just 1
1 and 10 together
1,4,5,10 (4 attributes)
These need to enter the table as a single "batch" against a (new?) productAttributeId
So if (1,10) was chosen, this needs to be blocked because 1-2 and 10-2 already exist.
What I suggest
The stored procedure should take the attributes as a single list, e.g. '1,2,3' (comma separated, no spaces, just integers)
You can then use a string splitting UDF or an inline XML trick (as shown below) to break it into rows of a derived table.
Test table
create table attrib (attributeid int, productattributeid int)
insert attrib select 1,1
insert attrib select 1,2
insert attrib select 10,2
Here I use a variable, but you can incorporate as a SP input param
declare #t nvarchar(max) set #t = '1,2,10'
select top(1)
t.productattributeid,
count(t.productattributeid) count_attrib,
count(*) over () count_input
from (select convert(xml,'<a>' + replace(#t,',','</a><a>') + '</a>') x) x
cross apply x.x.nodes('a') n(c)
cross apply (select n.c.value('.','int')) a(attributeid)
left join attrib t on t.attributeid = a.attributeid
group by t.productattributeid
order by countrows desc
Output
productattributeid count_attrib count_input
2 2 3
The 1st column gives you the productattributeid that has the most matches
The 2nd column gives you how many attributes were matched using the same productattributeid
The 3rd column is how many attributes exist in the input
If you compare the last 2 columns and the counts
match - you can use the productattributeid to attach to the product which has all these attributes
don't match - then you need to do an insert to create a new combination