In SQL Server, I've a table name URL_DATA with two column Domain and URL. Column URL contains address of different site for example "https://stackoverflow.com/questions/ask". How can I extract "stackoverflow.com" from it? OR How can I copy string "stackoverflow.com" in new column Domain?
Input Table:
| Domain | URL |
| ------ | ---------------------------------------------------- |
| | https://www.youtube.com/ |
| | https://www.youtube.com/feed/library |
| | https://www.red-gate.com/simple-talk/sql/sql-training|
| | https://internshala.com/student/dashboard |
| | https://stackoverflow.com/questions/ask |
Expected Output Table:
| Domain | URL |
| ----------------- | ---------------------------------------------------- |
| youtube.com | https://www.youtube.com/ |
| youtube.com | https://www.youtube.com/feed/library |
| red-gate.com | https://www.red-gate.com/simple-talk/sql/sql-training|
| internshala.com | https://internshala.com/student/dashboard |
| stackoverflow.com | https://stackoverflow.com/questions/ask |
I have tired using this:
update URL_DATA set domain = replace(replace(replace(domain,'',''),'https://',''),'www.','');
But unable to remove trailing characters.
I tried using this and it worked.
DECLARE #N2 VARCHAR(255);
DECLARE #N1 INT;
DECLARE C1 CURSOR FOR SELECT Domain FROM URL_DATA ;
OPEN C1
FETCH NEXT FROM C1 INTO #N2
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE URL_DATA SET Domain = REPLACE(REPLACE(REPLACE(#N2,'http://',''),'https://',''),'www.','') where CURRENT OF C1
FETCH NEXT FROM C1 INTO #N2
END
CLOSE C1
OPEN C1
FETCH NEXT FROM C1 INTO #N2
WHILE ##FETCH_STATUS = 0
BEGIN
SET #N1= CHARINDEX('/',#N2)
IF (#N1>0)
BEGIN
UPDATE URL_DATA SET Domain = SUBSTRING(#N2,1,ABS(CHARINDEX('/',#N2)-1)) where CURRENT OF C1
END
FETCH NEXT FROM C1 INTO #N2
END
CLOSE C1
DEALLOCATE C1;
Related
Is there an out-of-the-box method for Snowflake to use values from a column as a filename when using COPY INTO #mystage? The goal is to copy X number of files into an s3 stage (essentially PARTITION BY column1), but straight to the stage, not creating subfolders. X would be the number of distinct values in a column.
This can obviously be done manually:
copy into #mystage/mycustomfilename
However, the better option would be something like this:
copy into #mystage/$column1
Is there a version of this that Snowflake supports?
As mentioned above, the PARTITION BY setting parses data into subfolders and the subfolders are named using the values in the specified column, but Snowflake still uses a generic filename within each subfolder.
Created structure -
create temporary table temp_tab_split_members(seq_id number, member_id number, name varchar2(30));
+----------------------------------------------------+
| status |
|----------------------------------------------------|
| Table TEMP_TAB_SPLIT_MEMBERS successfully created. |
+----------------------------------------------------+
Fake data -
insert into temp_tab_split_members
with cte as
(select seq4(),(trim(mod(seq4(),4))+1)::integer,'my name-'||seq4() from table(generator(rowcount=>12)))
select * from cte;
+-------------------------+
| number of rows inserted |
|-------------------------|
| 12 |
+-------------------------+
Checking data format -
select * from TEMP_TAB_SPLIT_MEMBERS order by member_id;
+--------+-----------+------------+
| SEQ_ID | MEMBER_ID | NAME |
|--------+-----------+------------|
| 0 | 1 | my name-0 |
| 4 | 1 | my name-4 |
| 8 | 1 | my name-8 |
| 1 | 2 | my name-1 |
| 5 | 2 | my name-5 |
| 9 | 2 | my name-9 |
| 2 | 3 | my name-2 |
| 6 | 3 | my name-6 |
| 10 | 3 | my name-10 |
| 3 | 4 | my name-3 |
| 7 | 4 | my name-7 |
| 11 | 4 | my name-11 |
+--------+-----------+------------+
Checked stage is empty
list #test_row_stage;
+------+------+-----+---------------+
| name | size | md5 | last_modified |
|------+------+-----+---------------|
+------+------+-----+---------------+
Main procedure to generate files
EXECUTE IMMEDIATE $$
DECLARE
company varchar2(30);
BU varchar2(30);
eval_desc varchar2(30);
member_id varchar2(30);
file_name varchar2(30);
c1 CURSOR FOR SELECT distinct member_id FROM temp_tab_split_members;
BEGIN
for record in c1 do
member_id:=record.member_id;
file_name:='load'||'_'||member_id||'.csv';
execute immediate 'copy into #test_row_stage/'||:file_name||' from
(select * from temp_tab_split_members where member_id='||:member_id||') overwrite=false';
end for;
RETURN 0;
END;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 0 |
+-----------------+
Check stage contents after procedure execution
list #test_row_stage; -- output truncated columnwise
+----------------------------------------+------+
| name | size |
|----------------------------------------+------+
| test_row_stage/load_1.csv_0_0_0.csv.gz | 48 |
| test_row_stage/load_2.csv_0_0_0.csv.gz | 48 |
| test_row_stage/load_3.csv_0_0_0.csv.gz | 48 |
| test_row_stage/load_4.csv_0_0_0.csv.gz | 48 |
File contents cross-check
select $1,$2,$3 from #test_row_stage/load_1.csv_0_0_0.csv.gz union
select $1,$2,$3 from #test_row_stage/load_2.csv_0_0_0.csv.gz union
select $1,$2,$3 from #test_row_stage/load_3.csv_0_0_0.csv.gz union
select $1,$2,$3 from #test_row_stage/load_4.csv_0_0_0.csv.gz;
+----+----+------------+
| $1 | $2 | $3 |
|----+----+------------|
| 0 | 1 | my name-0 |
| 4 | 1 | my name-4 |
| 8 | 1 | my name-8 |
| 1 | 2 | my name-1 |
| 5 | 2 | my name-5 |
| 9 | 2 | my name-9 |
| 2 | 3 | my name-2 |
| 6 | 3 | my name-6 |
| 10 | 3 | my name-10 |
| 3 | 4 | my name-3 |
| 7 | 4 | my name-7 |
| 11 | 4 | my name-11 |
+----+----+------------+
There is no OOB for this as I understand, but you can write custom code and fetch values and use them to name files and copy them to stage/s3.
Please refer below for something similar -
EXECUTE IMMEDIATE $$
DECLARE
company varchar2(30);
BU varchar2(30);
eval_desc varchar2(30);
member_id varchar2(30);
file_name varchar2(30);
c1 CURSOR FOR SELECT * FROM test_pivot;
BEGIN
for record in c1 do
company:=record.company;
BU:=record.BU;
eval_desc:=record.eval_desc;
member_id:=record.member_id;
file_name:='load'||'_'||member_id||'.csv';
create or replace temporary table temp_test_pvt(company varchar2(30),BU varchar2(30),eval_desc varchar2(30),member_id varchar2(30));
insert into temp_test_pvt values (:company,:bu,:eval_desc,:member_id);
execute immediate 'copy into #test_row_stage/'||:file_name||' from (select * from temp_test_pvt) overwrite=false';
end for;
RETURN 0;
END;
$$
;
Also, refer a similar post here -
Copy JSON data from Snowflake into S3
I have a cursor that iterates through my temporary table. While it's iterating, I want to check a condition and delete some rows depending on the condition (I will be deleting rows that the iterator has not reached yet).
I tried deleting rows from the table the cursor is iterating (so the temp table), but no success, I can see them in the Messages panel (I print its name).
Is it possible to delete rows from the table a cursor is iterating in SQL-Server ? If it's not, what are my alternatives ?
Basically, the temp table contains tree-like data and depending on the value of a column, I need to delete its children (and grand-children and so on) if it does not fit a criteria.
DECLARE cursor_name CURSOR
FOR (SELECT * FROM #test) ORDER BY Path
DECLARE
#Id AS INTEGER,
#Name AS VARCHAR(MAX),
#Path AS VARCHAR(MAX)
OPEN cursor_name;
FETCH NEXT FROM cursor_name INTO #Id, #Name, #Path;
PRINT #Name
DELETE FROM #test
WHERE
Path LIKE '%76939%'
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM cursor_name INTO #Id, #Name, #Path;
PRINT #Name
END;
CLOSE cursor_name;
DEALLOCATE cursor_name;
#EDIT
Here is more detail on the problem. We have data structured like a tree list. Every item has multiple columns that specify some characteristics the row. Those characteristics can be inherited or not (if InheritanceFlag is 1, then it's inherited, if it's 0, then it is not).
So, when a user makes a change, we need to propagate the change to its children, depending on the said flag. If one of its child has the InheritanceFlag set to 0, then it won't change its value and neither will its children. I wanted to remove those rows with the cursor using the path.
Here is the data that I have. ParentID is the ID of its parent. In this case, suppose we are editing the item 76938, thus we are looking at its children. The ToEdit column is what I'm looking to create; with it, I can filter the rows and directly change the characteristic column to the new value.
+-------+----------+-------+-------------------------+-----------------+--------+
| ID | ParentID | Name | Path | InheritanceFlag | ToEdit |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76938 | NULL | 1 | (76938) | 1 | X |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76942 | 76938 | 1.1 | (76938)\(76942) | 1 | 1 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76952 | 76942 | 1.1.1 | (76938)\(76942)\(76952) | 0 | 0 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76961 | 76942 | 1.1.2 | (76938)\(76942)\(76961) | 1 | 1 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76943 | 76938 | 1.2 | (76938)\(76943) | 1 | 1 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76944 | 76938 | 1.3 | (76938)\(76944) | 0 | 0 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76946 | 76944 | 1.3.1 | (76938)\(76944)\(76946) | 1 | 0 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76947 | 76944 | 1.3.2 | (76938)\(76944)\(76947) | 0 | 0 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76948 | 76944 | 1.3.3 | (76938)\(76944)\(76948) | 1 | 0 |
+-------+----------+-------+-------------------------+-----------------+--------+
| 76945 | 76938 | 1.4 | (76938)\(76945) | 1 | 1 |
+-------+----------+-------+-------------------------+-----------------+--------+
You can delete from the underlying table and have the rows removed from future FETCHes if the cursor is DYNAMIC, and the query that defines the cursor doesn't require a spool, effectively turning it into a STATIC cursor.
In your code sorting by the unindexed VARCHAR(MAX) prevents the cursor from seeing any changes in the underlying table.
EG this
drop table if exists #test
go
create table #test(id integer, name varchar(max), path varchar(1000), index ix_path (path))
insert into #test(id,name,path) values (1,'a','0000000'),(2,'b', '0769391'),(3,'c', '1768391')
DECLARE cursor_name CURSOR DYNAMIC
FOR SELECT * FROM #test ORDER BY path
DECLARE
#Id AS INTEGER,
#Name AS VARCHAR(MAX),
#Path AS VARCHAR(MAX)
OPEN cursor_name;
FETCH NEXT FROM cursor_name INTO #Id, #Name, #Path;
PRINT #Name
print 'deleting'
DELETE FROM #test
WHERE
Path LIKE '%76939%'
WHILE 1=1
BEGIN
FETCH NEXT FROM cursor_name INTO #Id, #Name, #Path;
if ##FETCH_STATUS <> 0 break
PRINT #Name
END;
CLOSE cursor_name;
DEALLOCATE cursor_name;
outputs
(3 rows affected)
a
deleting
(1 row affected)
c
I am working with XML data on an SQL Server. The (exemplary) SQL looks as follows:
<Document xmlns="urn:iso:std:iso:20022:some:test:xmlns">
<Testnode>a</Testnode>
</Document>
The XML is available in a table with a column named <fata of type XML.
My question is: How can I create a SELECT query that shows the text of the namespace in one column?
The expected output should be:
+----------------------------------------+
| xmlns |
+----------------------------------------+
| urn:iso:std:iso:20022:some:test:xmlns |
+----------------------------------------+
The result column should be a character string (no XML).
So far I have tried this query, however the result is NULL:
SELECT Data.value('(./Document)[1]','nvarchar(max)') AS xmlns
FROM xmltable
You can try something along this:
DECLARE #xml XML=
N'<Document xmlns="urn:iso:std:iso:20022:some:test:xmlns">
<Testnode>a</Testnode>
</Document>';
--The XQuery-function namespace-uri() takes a singleton and returns its namespace uri
SELECT #xml.value('namespace-uri((/*:Document)[1])','nvarchar(max)');
As the <Document> element is living within the default namespace itself, we would have to know the namespace in advance in order to declare it. But - luckily - we can use the wildcard with *:.
Another option - one of the rare cases - is the usage of the outdated FROM OPENXML:
Try this:
DECLARE #xml XML=
N'<Document xmlns="urn:iso:std:iso:20022:some:test:xmlns">
<Testnode>a</Testnode>
</Document>';
DECLARE #docHandle INT;
EXEC sp_xml_preparedocument #docHandle OUTPUT, #xml;
SELECT * FROM OPENXML (#docHandle, '/*',1);
EXEC sp_xml_removedocument #docHandle;
This returns the complete XML with a lot of meta-data:
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| id | parentid | nodetype | localname | prefix | namespaceuri | datatype | prev | text |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 0 | NULL | 1 | Document | NULL | urn:iso:std:iso:20022:some:test:xmlns | NULL | NULL | NULL |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 2 | 0 | 2 | xmlns | xmlns | NULL | NULL | NULL | NULL |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 4 | 2 | 3 | #text | NULL | NULL | NULL | NULL | urn:iso:std:iso:20022:some:test:xmlns |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 3 | 0 | 1 | Testnode | NULL | urn:iso:std:iso:20022:some:test:xmlns | NULL | NULL | NULL |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 5 | 3 | 3 | #text | NULL | NULL | NULL | NULL | a |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
I'm having trouble changing a column value based on a value from the same column.
If the "setting_id" of D244 has a "setting_value" of 1, then I need to change " 8F60 to 1 as well.
Here is a sample datatable settings
| setting_id | setting_value |
| ---------- | ------------- |
| D244 | 1 |
| 8F60 | 0 |
| AD4F | 1 |
settings
My attempt:
UPDATE settings s, (SELECT DISTINCT setting_id, setting_value FROM settings WHERE setting_value like '1' and setting_id like 'D244') s1
SET s.settingValue = s1.settingValue
WHERE s.settingID like '8F60'
Try this -
UPDATE settings s INNER JOIN settings s1
ON s1.setting_id = s.setting_id
SET s.settingValue = s1.settingValue
WHERE s.settingID like '8F60'
AND s1.setting_id = 'D244'
I have a table in my database as follows:
+-------+
| Name |
+-------+
| A |
| B |
| C,D |
| A,B,E |
+-------+
I want the output as
+------+
| Name |
+------+
| A |
| B |
| C |
| D |
| E |
+------+
My question is how to retrieve C,D and A,B,E into different rows?
First create a custom split() function.
Split Function
CREATE FUNCTION dbo.Split(#String nvarchar(4000), #Delimiter char(1))
RETURNS #Results TABLE (colA nvarchar(4000))
AS
BEGIN
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
SELECT #INDEX = 1
WHILE #INDEX !=0
BEGIN
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
IF #INDEX !=0
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
ELSE
SELECT #SLICE = #STRING
INSERT INTO #Results(colA) VALUES(#SLICE)
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
IF LEN(#STRING) = 0 BREAK
END
RETURN
END
Table
CREATE TABLE names(name VARCHAR(MAX));
INSERT INTO names VALUES('A');
INSERT INTO names VALUES('B');
INSERT INTO names VALUES('C,D');
INSERT INTO names VALUES('A,B,E');
SELECT * FROM names;
Table Structure
+-------+
| name |
+-------+
| A |
| B |
| C,D |
| A,B,E |
+-------+
Then assign all the values as comma separated to a variable.
DECLARE #str VARCHAR(MAX)
SELECT #str=t.csv FROM (SELECT SUBSTRING(
(SELECT ',' + n.name
FROM names n
ORDER BY n.name
FOR XML PATH('')),2,200000) AS csv)t;
SELECT DISTINCT colA AS Name FROM Split(#str,',');
Result
+------+
| Name |
+------+
| A |
| B |
| C |
| D |
| E |
+------+
Fiddle Demo Here
Hope this will help you out.