Update data inside a view in SQL server - sql-server

I have some data that looks as follows
As seen, the req_uri column, has data that contains ids after the second slash. I am only interested in the stem of the uri, that is the part before the second uri.
How can I create a view, where the req_uri is updated to only contain values in either '/v1/org' or '/v1/registration'
event_id req_uri
0007845f-cf6c-4513-9a5f-96d02482ef78 /v1/org/6970b2a5-e220-4d68-8fc0-2992a1b8bdb7
000a1fb0-ac4d-489e-866a-7c07caebb959 /v1/registration
000fe2a9-6d76-4045-93ac-9df68971539c /v1/org/6970b2a5-e220-4d68-8fc0-2992a1b8bdb7
0017e50b-c7b5-4e42-b670-f2d9f0af752f /v1/org/e536c1ed-4822-4b88-8c01-9f14c1c583e3/apps
0025a81f-cf81-4c60-8a39-3a626c1092a3 /v1/org/6970b2a5-e220-4d68-8fc0-2992a1b8bdb7
00304cef-87f3-426b-984c-b0b906b4815a /v1/org/e536c1ed-4822-4b88-8c01-9f14c1c583e3/apps
I know how to create views, as follows
CREATE VIEW V_MyView
AS SELECT event_id, req_uri
FROM tableName;
I also know how trim it as follows
update req_uri set req_uri = '/v1/org' where req_uri like '/v1/org%'
However, how can I combine this inside of a view, so that it contains the trimmed data?

Not sure I follow your question 100%, but I think you are asking how to make a view that has an altered hard-coded manipulation of req_uri, so something like this is what you want:
CREATE VIEW V_MyView
AS
SELECT event_id,
CASE WHEN req_uri LIKE '/v1/org%' THEN '/v1/org'
WHEN req_uri LIKE '/v1/registration%' THEN '/v1/registration'
ELSE NULL END as [req_uri]
FROM tableName;

Related

SQL Server - add to this query to first check for existence of a string

I have an nvarchar field in my database called CatCustom which contains comma-separated 5-character codes. It can contain as little as one code, or as many as 20 codes, separated by commas.
Right now, I use this query to add a new 5-character code to the field in given records (in this case the new code is LRR01):
UPDATE dbo.Sources
SET CatCustom = CONCAT_WS(', ', RTRIM(CatCustom), 'LRR01')
WHERE SourceID IN (1,2,3,4,5,8,9,44,63,45,101,102,222,344)
I need to add to this though: I need the record to be updated only if that 5-character code doesn't already exist somewhere in the CatCustom field, to ensure that code is not in there more than once.
How would I accomplish this?
EDIT: I really don't understand how this can be considered a duplicate of the suggested thread. This is a VERY specific case and has nothing to do with creating stored procedures and or variables. The alleged duplicated thread does not really help me - sorry.
Use STRING_SPLIT function to split the comma separated list and then add Not Exist condition in the WHERE clause like below
UPDATE dbo.Sources
SET CatCustom = CONCAT_WS(', ', RTRIM(CatCustom), 'LRR01')
WHERE SourceID IN (1,2,3,4,5,8,9,44,63,45,101,102,222,344)
AND NOT EXISTS (SELECT 1 FROM STRING_SPLIT(CatCustom, ',') where value = 'LRR01')
UPDATE dbo.Sources
SET
CatCustom = CONCAT_WS(', ', RTRIM(CatCustom), 'LRR01')
WHERE
SourceID IN (1,2,3,4,5,8,9,44,63,45,101,102,222,344)
AND CatCustom NOT LIKE '%LRR01%';

How do you add attributes to an existing Root XML Node using TSQL?

I've constructed some XML in TSQL.
declare #requestXML xml
set #requestXML = (
select #dataXML
for xml raw ('rtEvent')
The general output for what I now have follows the pattern resembling this:
<rtEvent>
<ctx>
.....
</ctx>
</rtEvent>
What I'd like to do now is add some attributes and values to the rtEvent root
element node but I'm not certain how to achieve it.
I've looked at the Modify method of the XML object and have observed the insert, replace value of, and delete operations but cannot seem to figure out how to use any of them to achieve the results I'm after.
Basically, I want to be able to modify the root node to reflect something like:
<rtEvent type="customType" email="someaddress#domain.com"
origin="eCommerce" wishedChannel="0" externalId="5515">
<ctx>
...
</ctx>
</rtEvent>
Should I be using the documented XML.Modify or is there a better method? How should it be done?
Just in case you wanted to see the modify method way of doing it:
DECLARE #requestXML XML = '<rtEvent><ctx>...</ctx></rtEvent>'
SET #requestXML.modify(
'insert
(
attribute type {"customeType"},
attribute email {"someaddress#domain.com"},
attribute origin {"eCommerce"},
attribute wishedChannel {"0"},
attribute externalId {"5515"}
)
into (/rtEvent)[1]')
SELECT #requestXML
it returns this:
<rtEvent type="customeType" email="someaddress#domain.com" origin="eCommerce" wishedChannel="0" externalId="5515">
<ctx>...</ctx>
</rtEvent>
Better use FOR XML PATH, which allows you to specify the naming and aliases as you like them:
SELECT 'SomeContext' AS [ctx]
FOR XML PATH('rtEvent')
This will return this:
<rtEvent>
<ctx>SomeContext</ctx>
</rtEvent>
But with the right attributes you get this:
SELECT 'customType' AS [#type]
,'someaddress#domain.com' AS [#email]
,'eCommerce' AS [#origin]
,0 AS [#wishedChannel]
,5515 AS [#externalId]
,'SomeContext' AS [ctx]
FOR XML PATH('rtEvent')
The result
<rtEvent type="customType" email="someaddress#domain.com" origin="eCommerce" wishedChannel="0" externalId="5515">
<ctx>SomeContext</ctx>
</rtEvent>

Access 2013 ComboBox based on Combobox with Junction Table

Good day. I would like to know why a Parameter Request pops up when executing a query. I have a form with 2 comboboxes where the 2nd one depends on the value in the 1st one. I do know how to do this when it involves 2 tables. I am having trouble when there is a many to many relationship.
Table 1: name - Supply_Sources, fields - Source_ID(pk), SupplySourceName
Table 2: name - Warehouse_Locations, fields - WLocation_ID(pk), Location_Name
Table 3 (junction): name - SupplySource_WarehouseLocation, fields - Supply_Source_ID(pk), Location_In_ID(pk)
On my form frmInventoryReceivedInput I have cboSupplySource and cboWLocation.
I populate cboSupplySource with
SELECT [Supply_Sources].[Source_ID], [Supply_Sources].[SupplySourceName] FROM Supply_Sources;
I am trying to get a drop down list in the cboWLocation based on the value in cboSupplySource. I am wanting to see the location names of where the supplies are placed in the warehouse.
I have a requery in cboSupplySource After Update (with cboWLocation as the control name). The SQL that I have come up with so far is:
SELECT Warehouse_Locations.Location_Name,
SupplySource_WarehouseLocation.Supply_Source_ID,
SupplySource_WarehouseLocation.Location_In_ID
FROM Warehouse_Locations RIGHT JOIN (Supply_Sources LEFT JOIN
SupplySource_WarehouseLocation ON Supply_Sources.Source_ID =
SupplySource_WarehouseLocation.Supply_Source_ID) ON
Warehouse_Locations.WLocation_ID =
SupplySource_WarehouseLocation.Location_In_ID
WHERE (((Warehouse_Locations.Location_Name)=[frmInventoryReceivedInput].[cboSupplySource]));
When it runs, on tabbing out of cboSupplySource, Enter Parameter Value dialogue box pops up, looking for frmInventoryReceivedInput.cboSupplySource input. Nothing I input brings up the correct list in cboWLocation.
Obviously, I do not have the correct select statement. Any help would be appreciated.
For cboWLocation try the recordSource query:
SELECT Warehouse_Locations.Location_Name
FROM Warehouse_Locations INNER JOIN (Supply_Sources INNER JOIN
SupplySource_WarehouseLocation ON Supply_Sources.Source_ID =
SupplySource_WarehouseLocation.Supply_Source_ID) ON
Warehouse_Locations.WLocation_ID =
SupplySource_WarehouseLocation.Location_In_ID
WHERE ((Supply_Sources.SupplySourceName)=([Forms]![frmInventoryReceivedInput].[cboSupplySource]))
Be aware, that the combobox columns have to be set to columncount 1 in this case with appropriate column width, because you said you only want to see the location names. Further, you should be sure that cboWLocation is not bound to a Control Source, to not overwrite anything.
You can apply it in VBA at the cboWLocation Enter Event.
In the following code example, the combobox cboWLocation is only updated, if there is a value in combobox cboSupplySource.
Private Sub cboWLocation_Enter()
If not (isNull(Me!cboSupplySource) Or Me!cboSupplySource.ListIndex = -1) then
Me.cboWLocation.RowSource = strSQL 'Put here the previous mentioned SQLString
End if
End Sub
HINT: It would be better for performance, when you change the bound column in cboSupplySource to the PK SourceID instead of the name. (With two columns in combobox cboSupplySource) Then use this PK to compare in your WHERE statement instead of the name. this is what keys in tables are for.
Edit: In the WHERE statement, maybe you have to put the namecomparison between ' ' because it is a string

UPDATE only a part of a string value in a column

I am new to t-sql. I have a column which stores values as url's. I want to change the first part of the url's (string), and replace only this part with another url. For example, [url//lsansps01/PMO/ITG0038 iSCOMBI Data Model Project] to [url2//lwazitest.lionsure.com/PMO/ITG0038 iSCOMBI Data Model Project]
This is my update query:
UPDATE dbo.RowUpdates
SET ProjectWorkspaceInternalHRef = REPLACE ProjectWorkspaceInternalHRef, url//lsansps01/, url2//lwazitest.lionsure.com/PMO/ITG0038 iSCOMBI Data Model Project
FROM RowUpdates
WHERE ProjectWorkspaceInternalHRef LIKE url
REPLACE uses () and not comma delimited parameters,
UPDATE dbo.RowUpdates
SET ProjectWorkspaceInternalHRef = REPLACE(ProjectWorkspaceInternalHRef, 'url//lsansps01/', 'url2//lwazitest.lionsure.com/PMO/ITG0038 iSCOMBI Data Model Project')
FROM RowUpdates
WHERE ProjectWorkspaceInternalHRef LIKE url
another questionable part is LIKE url for it to work there should be '%'+url+'%' or something similar.
You want to look at MSDN: REPLACE (Transact-SQL)
from the article:
REPLACE ( string_expression , string_pattern , string_replacement )
so you'd want to change your replace statement to (remember to use a quote (') around your strings):
UPDATE dbo.RowUpdates
SET ProjectWorkspaceInternalHRef =
REPLACE(ProjectWorkspaceInternalHRef, 'url//lsansps01/', 'url2//lwazitest.lionsure.com/PMO/ITG0038 iSCOMBI Data Model Project')
FROM RowUpdates
WHERE ProjectWorkspaceInternalHRef LIKE url
It's also worth looking at the list of String Functions (Transact-SQL) you get in SQL Server.
Replace() function will not give your expected results if #OldUrl text is found in the middle of the ProjectWorkspaceInternalHRef.
If you want to replace only the front bit, use RIGHT() (or SUBSTRING()) function after filtering them out with LEFT() function.
DECLARE #OldUrl VARCHAR(500) = 'YourOdlUrl',
#NewUrl VARCHAR(500) = 'YourNewUrl'
UPDATE dbo.RowUpdates
SET ProjectWorkspaceInternalHRef = #NewUrl +
RIGHT(ProjectWorkspaceInternalHRef, LEN(ProjectWorkspaceInternalHRef) - LEN(#OldUrl ))
WHERE LEFT(ProjectWorkspaceInternalHRef, LEN(#OldUrl )) = #OldUrl

How do I update an XML column in sql server by checking for the value of two nodes including one which needs to do a contains (like) comparison

I have an xml column called OrderXML in an Orders table...
there is an XML XPath like this in the table...
/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail
There InternalOrderDetails contains many InternalOrderDetail nodes like this...
<InternalOrderDetails>
<InternalOrderDetail>
<Item_Number>FBL11REFBK</Item_Number>
<CountOfNumber>10</CountOfNumber>
<PriceLevel>FREE</PriceLevel>
</InternalOrderDetail>
<InternalOrderDetail>
<Item_Number>FCL13COTRGUID</Item_Number>
<CountOfNumber>2</CountOfNumber>
<PriceLevel>NONFREE</PriceLevel>
</InternalOrderDetail>
</InternalOrderDetails>
My end goal is to modify the XML in the OrderXML column IF the Item_Number of the node contains COTRGUID (like '%COTRGUID') AND the PriceLevel=NONFREE. If that condition is met I want to change the PriceLevel column to equal FREE.
I am having trouble with both creating the xpath expression that finds the correct nodes (using OrderXML.value or OrderXML.exist functions) and updating the XML using the OrderXML.modify function).
I have tried the following for the where clause:
WHERE OrderXML.value('(/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/Item_Number/node())[1]','nvarchar(64)') like '%13COTRGUID'
That does work, but it seems to me that I need to ALSO include my second condition (PriceLevel=NONFREE) in the same where clause and I cannot figure out how to do it. Perhaps I can put in an AND for the second condition like this...
AND OrderXML.value('(/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/PriceLevel/node())[1]','nvarchar(64)') = 'NONFREE'
but I am afraid it will end up operating like an OR since it is an XML query.
Once I get the WHERE clause right I will update the column using a SET like this:
UPDATE Orders SET orderXml.modify('replace value of (/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/PriceLevel[1]/text())[1] with "NONFREE"')
However, I ran this statement on some test data and none of the XML columns where updated (even though it said zz rows effected).
I have been at this for several hours to no avail. Help is appreciated. Thanks.
if you don't have more than one node with your condition in each row of Orders table, you can use this:
update orders set
data.modify('
replace value of
(
/Order/InternalInformation/InternalOrderBreakout/
InternalOrderHeader/InternalOrderDetails/
InternalOrderDetail[
Item_Number[contains(., "COTRGUID")] and
PriceLevel="NONFREE"
]/PriceLevel/text()
)[1]
with "FREE"
');
sql fiddle demo
If you could have more than one node in one row, there're a several possible solutions, none of each is really elegant, sadly.
You can reconstruct all xmls in table - sql fiddle demo
or you can do your updates in the loop - sql fiddle demo
This may get you off the hump.
Replace #HolderTable with the name of your table.
SELECT T2.myAlias.query('./../PriceLevel[1]').value('.' , 'varchar(64)') as MyXmlFragmentValue
FROM #HolderTable
CROSS APPLY OrderXML.nodes('/InternalOrderDetails/InternalOrderDetail/Item_Number') as T2(myAlias)
SELECT T2.myAlias.query('.') as MyXmlFragment
FROM #HolderTable
CROSS APPLY OrderXML.nodes('/InternalOrderDetails/InternalOrderDetail/Item_Number') as T2(myAlias)
EDIT:
UPDATE
#HolderTable
SET
OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue"')
WHERE
OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel)[1]', 'varchar(64)') = 'FREE'
print ##ROWCOUNT
Your issue is the [1] in the above.
Why did I put it there?
Here is a sentence from the URL listed below.
Note that the target being updated must be, at most, one node that is explicitly specified in the path expression by adding a "[1]" at the end of the expression.
http://msdn.microsoft.com/en-us/library/ms190675.aspx
EDIT.
I think I've discovered the the root of your frustration. (No fix, just the problem).
Note below, the second query works.
So I think the [1] is some cases is saying "only ~~search~~ the first node".....and not (as you and I were hoping)...... "use the first node..after you find a match".
UPDATE
#HolderTable
SET
OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue001"')
WHERE
OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel[text() = "NONFREE"])[1]', 'varchar(64)') = 'NONFREE'
/* and OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/Item_Number)[1]', 'varchar(64)') like '%COTRGUID' */
UPDATE
#HolderTable
SET
OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue002"')
WHERE
OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel[text() = "FREE"])[1]', 'varchar(64)') = 'FREE'
Try this :
;with InternalOrderDetail as (SELECT id,
Tbl.Col.value('Item_Number[1]', 'varchar(40)') Item_Number,
Tbl.Col.value('CountOfNumber[1]', 'int') CountOfNumber,
case
when Tbl.Col.value('Item_Number[1]', 'varchar(40)') like '%COTRGUID'
and Tbl.Col.value('PriceLevel[1]', 'varchar(40)')='NONFREE'
then 'FREE'
else
Tbl.Col.value('PriceLevel[1]', 'varchar(40)')
end
PriceLevel
FROM (select id ,orderxml from demo)
as a cross apply orderxml.nodes('//InternalOrderDetail')
as
tbl(col) ) ,
cte_data as(SELECT
ID,
'<InternalOrderDetails>'+(SELECT ITEM_NUMBER,COUNTOFNUMBER,PRICELEVEL
FROM InternalOrderDetail
where ID=Results.ID
FOR XML AUTO, ELEMENTS)+'</InternalOrderDetails>' as XML_data
FROM InternalOrderDetail Results
GROUP BY ID)
update demo set orderxml=cast(xml_data as xml)
from demo
inner join cte_data on demo.id=cte_data.id
where cast(orderxml as varchar(2000))!=xml_data;
select * from demo;
SQL Fiddle
I have handled following cases :
1. As required both where clause in question.
2. It will update all <Item_Number> like '%COTRGUID' and <PriceLevel>= NONFREE in one
node, not just the first one.
It may require minor changes for your data and tables.

Resources