inserting new recording and updating the foreignkey - tsql

I have tables like this
MainTable
Id FolderName Description UserId
1 Folder1 Description1 1
2 Folder1 Description2 1
3 Folder1 Desctiption3 1
4 Folder2 Description1 2
5 Folder2 Description2 2
ChildTable
Id FolderId Title UserId imageName
1 1 AA 1 AAA
2 1 BB 1 BBB
3 2 CC 1 CCC
4 3 DD 1 DDD
5 4 EE 2 EEE
I want to select all records in MainTable and ChildTable For userId=1 and insert them again into MainTable/ChildTable but with UserId=5, so the FolderId for the new records should be updated, so the result should be like this:
Id FolderName Description UserId
1 Folder1 Description1 1
2 Folder1 Description2 1
3 Folder1 Desctiption3 1
4 Folder2 Description1 2
5 Folder2 Description2 2
6 Folder1 Description1 5
7 Folder1 Description2 5
8 Folder1 Desctiption3 5
Id FolderId Title UserId imageName
1 1 AA 1 AAA
2 1 BB 1 BBB
3 2 CC 1 CCC
4 3 DD 1 DDD
5 4 EE 2 EEE
6 6 AA 5 AAA
7 6 BB 5 BBB
8 7 CC 5 CCC
9 8 DD 5 DDD
how can i do that?
thank you

Try this:
DECLARE #t table (OldFolderId int, NewFolderId int);
MERGE MainTable AS m
USING (SELECT Id, FolderName, Description
FROM MainTable AS m
WHERE UserId = 1) AS src
ON 1=2
WHEN NOT MATCHED THEN
INSERT (FolderName, Description, UserId)
VALUES (src.FolderName, src.Description, 5)
OUTPUT src.Id AS OldFolderId, inserted.Id AS NewFolderId
INTO #t;
INSERT ChildTable (FolderId, Title, UserId, imageName)
SELECT t.NewFolderId, Title, 5, imageName
FROM ChildTable c
INNER JOIN #t t ON t.OldFolderId = c.FolderID
WHERE c.UserId = 1;
SQLFiddle here

Related

How to group by total of occurrences and don't repeat records

I have these tables:
products:
id
title
1
product a
2
product b
3
product c
clicks:
id
product_id
created_at
1
1
2022-01-01
2
1
2022-03-02
3
2
2022-10-01
I need to have the following result:
product_id
total_clciks
1
2
2
1
How can I solve this?
Thanks

T-SQL: split string on multiple delimiters

I have been given a T-SQL task: to convert/format names which are in ALL CAPS into Title Case. I have decided that splitting the names into tokens, and capitalizing the first letter out of each token, would be a reasonable approach (I am willing to take advice if there's a better option, especially in T-SQL).
That said, to accomplish this, I'd have to split the name fields on spaces AND dashes, hyphens, etc. Then, once it is tokenized, I can worry about normalizing the case.
Is there any reasonable way to split a string along any delimiter in a list?
If ease & performance is important then grab a copy of PatExtract8k.
Here's a basic example where I split on any character that is not a letter or number ([^a-z0-9]):
-- Sample String
DECLARE #string VARCHAR(8000) = 'abc.123&xyz!4445556__5566^rrr';
-- Basic Use
SELECT pe.* FROM samd.patExtract8K(#string,'[^a-z0-9]') AS pe;
Output:
itemNumber itemIndex itemLength item
--------------- ----------- ----------- -------------
1 1 3 abc
2 5 3 123
3 9 3 xyz
4 13 7 4445556
5 22 4 5566
6 27 3 rrr
It returns what you need as well as:
the length of the item (ItemLength)
It's position in the string (ItemIndex)
It's ordinal position in the string (ItemNumber.)
Now against a table. Here we're doing the same thing but I'll explicitly call out the characters I want to use as a delimiter. Here it's any of these characters: *.&,?%/>
-- Sample Table
DECLARE #table TABLE (SomeId INT IDENTITY, SomeString VARCHAR(100));
INSERT #table VALUES('abc***332211,,XXX'),('abc.123&&555%jjj'),('ll/111>ff?12345');
SELECT t.*, pe.*
FROM #table AS t
CROSS APPLY samd.patExtract8K(t.SomeString,'[*.&,?%/>]') AS pe;
This returns:
SomeId SomeString itemNumber itemIndex itemLength item
----------- ------------------- ------------ ---------- ----------- ---------
1 abc***332211,,XXX 1 1 3 abc
1 abc***332211,,XXX 2 7 6 332211
1 abc***332211,,XXX 3 15 3 XXX
2 abc.123&&555%jjj 1 1 3 abc
2 abc.123&&555%jjj 2 5 3 123
2 abc.123&&555%jjj 3 10 3 555
2 abc.123&&555%jjj 4 14 3 jjj
3 ll/111>ff?12345 1 1 2 ll
3 ll/111>ff?12345 2 4 3 111
3 ll/111>ff?12345 3 8 2 ff
3 ll/111>ff?12345 4 11 5 12345
On the other hand - If I wanted to extract the delimiters I could change the pattern like this: [^*.&,?%/>]. Now the same query returns:
SomeId itemNumber itemIndex itemLength item
----------- -------------------- -------------------- ----------- ---------
1 1 4 3 ***
1 2 13 2 ,,
2 1 4 1 .
2 2 8 2 &&
2 3 13 1 %
3 1 3 1 /
3 2 7 1 >
3 3 10 1 ?

Replace empty strings with NULL instead of empty strings when using JOIN

I have two tables:
table_a
id name
1 john
2 dave
3 tim
4 marta
5 jim
table_b
id sum random_metric
1 10.50 abc
3 11.5 efg
5 5.76 ghj
I have joined them on id
SELECT ...
FROM table_a
LEFT JOIN table_b ON table_a.id = table_b.id
and I get:
id name sum random_metric
1 john 10.5 abc
2 dave
3 tim 11.5 efg
4 marta
5 jim 5.76 ghj
Then I want to convert the sum column to double precision but since it has empty strings in rows 2, 4 it does not work.
How could I join tables so that I would have this:
id name sum random_metric
1 john 10.5 abc
2 dave NULL NULL
3 tim 11.5 efg
4 marta NULL NULL
5 jim 5.76 ghj

Selecting Rows within Separate IDs until a first occurrence of given value

I am try to get all rows within each separate ID until the first occurrence of a given value, in this case "CR" but have to reverse the order of the rows. Here is how the data is stored on the table:
ID DebtMth YearMth Status Balance
1 5 2015-02 DR 10.00
1 4 2015-03 DR 10.00
1 3 2015-04 CR 00.00
1 2 2015-06 DR 10.00
1 1 2015-07 DR 10.00
2 10 2011-01 DR 20.00
2 9 2011-02 DR 20.00
2 8 2011-03 CR 20.00
3 11 2012-02 DR 30.00
3 10 2012-03 DR 30.00
3 8 2012-05 CR 00.00
3 7 2012-06 CR 00.00
3 6 2012-07 DR 30.00
I need to reverse the order so the last row within each ID group becomes the first and so on. So the table would be sorted as follows.
ID DebtMth YearMth Status Balance
1 1 2015-07 DR 10.00
1 2 2015-06 DR 10.00
1 3 2015-04 CR 00.00
1 4 2015-03 DR 10.00
1 5 2015-02 DR 10.00
2 8 2011-03 CR 20.00
2 9 2011-02 DR 20.00
2 10 2011-01 DR 20.00
3 6 2012-07 DR 30.00
3 7 2012-06 CR 00.00
3 8 2012-05 CR 00.00
3 10 2012-03 DR 30.00
3 11 2012-02 DR 30.00
Now I need to select rows within each ID group up until the Status is 'CR' and exclude any ID whose first row is 'CR'. So the output would look like this.
ID DebtMth YearMth Status Balance
1 1 2015-07 DR 10.00
1 2 2015-06 DR 10.00
3 6 2012-07 DR 30.00
I am using the Query Designer in Report Builder 3 connecting to an Microsoft SQL2012 Server.
I would very much appreciate any suggestions.
Martin
SELECT
id , DebtMth , YearMth , Status , Balance
FROM
(
SELECT
*
, MAX(CASE WHEN status = 'CR' THEN YearMth END) OVER(PARTITION BY id) AS first_cr_yearMth
FROM YourTable
) AS T
WHERE YearMth > first_cr_yearMth OR first_cr_yearMth IS NULL

Having data with Self Referencing Relationship

I have Tree like this
Folder0
|
|__Folder1
| |
| |_______Folder2
| | |_______Folder3
| | |_______Folder4
| |_______Folder5
| |_______Folder6
|__Folder7
Fields of the table are like this Id, fld_Id, Name, which fld_Id is the parent Id of the folder
Id , fld_Id , Name
________________________________
1 Null Folder0
2 Null Folder7
3 1 Folder1
4 3 Folder2
5 4 Folder3
6 4 Folder4
7 3 Folder5
7 3 Folder6
how can I get the List of the all directories which are located under the Folder1
which would be
Id , fld_Id , Name
________________________________
3 1 Folder1
4 3 Folder2
5 4 Folder3
6 4 Folder4
7 3 Folder5
7 3 Folder6
Try using recursive CTE like below :
;with CTE as
(
SELECT Id,fld_Id,Name FROM Test t1 WHERE Id = 3
UNION ALL
SELECT t1.Id, t1.fld_Id, t1.Name
FROM Test t1
INNER JOIN CTE ON t1.fld_Id = CTE.Id
)
SELECT * FROM CTE order by Id
SQL Fiddle Demo