I am trying to split a column('categories') of a Table 'movies_titles' which has string separated data values in it.
e.g:
ID title categories
1 Movie A Comedy, Drama, Romance
2 Movie B Animation
3 Movie C Documentary, Life changing
I want to split the comma delimited string and place each values in a separate rows and update the table
-- this query shows the splitted strings as I want it
SELECT *
FROM dbo.movies_titles
CROSS APPLY
string_split(categories, ',')
O/P:
ID title categories value
1 Movie A Comedy, Drama, Romance Comedy
1 Movie A Comedy, Drama, Romance Drama
1 Movie A Comedy, Drama, Romance Romance
2 Movie B Animation Animation
3 Movie C Documentary, Life changing Documentary
3 Movie C Documentary, Life changing Life changing
I want to use UPDATE query to set the result obtained from value column. I just don't want to use SELECT query to view the result but permanently update the changes to the table. How do I achieve this in sql server?
You can do something similar to your intention creating new rows, because the update statement won't create the additional rows made by the split.
There can be issues if the ID column is unique, like a primary key, and there is the need to keep the title associated with that column.
I've created two scenarios on DB Fiddle, showing how you can do this using only one table as the question instructed, but a better alternative would be to save this information on another table.
This code on DB Fiddle: link
--Assuming your table is something like this
create table movies_id_as_pk (
ID int identity(1,1) primary key,
title varchar(200),
categories varchar(200),
category varchar(200)
)
--Or this
create table movies_other_pk (
another_id int identity(1,1) primary key,
ID int,
title varchar(200),
categories varchar(200),
category varchar(200)
)
--The example data
set identity_insert movies_id_as_pk on
insert into movies_id_as_pk (ID, title, categories) values
(1, 'Movie A', 'Comedy, Drama, Romance'),
(2, 'Movie B', 'Animation'),
(3, 'Movie C', 'Documentary, Life changing')
set identity_insert movies_id_as_pk off
insert into movies_other_pk (ID, title, categories)
select ID, title, categories from movies_id_as_pk
--You can't update directly any of the tables, because as the result of the split
--have more rows than the table, it would just leave the first value found:
update m set category = rtrim(ltrim(s.value))
from movies_id_as_pk m
cross apply string_split(m.categories, ',') as s
update m set category = rtrim(ltrim(s.value))
from movies_other_pk m
cross apply string_split(m.categories, ',') as s
select * from movies_id_as_pk
select * from movies_other_pk
--What you can do is create the aditional rows, inserting them:
--First, let's undo what the last instructions have changed
update movies_id_as_pk set category=NULL
update movies_other_pk set category=NULL
--Then use inserts to create the rows with the categories split
insert into movies_id_as_pk (title, category)
select m.title, rtrim(ltrim(s.value))
from movies_id_as_pk m
cross apply string_split(m.categories, ',') as s
insert into movies_other_pk (ID, title, category)
select m.ID, m.title, rtrim(ltrim(s.value))
from movies_other_pk m
cross apply string_split(m.categories, ',') as s
select * from movies_id_as_pk
select * from movies_other_pk
It actually is possible to insert or update at the same time. That is to say: we can update each row with a single category, then create new rows for the extra ones.
We can use MERGE for this. We can use the same table as source and target. We just need to split the source, then add a row-number partitioned per each original row. We then filter the ON clause to match only the first row.
WITH Source AS (
SELECT
m.ID,
m.title,
category = TRIM(cat.value),
rn = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT NULL))
FROM movies m
CROSS APPLY STRING_SPLIT(m.categories, ',') cat
)
MERGE movies t
USING Source s
ON s.ID = t.ID AND s.rn = 1
WHEN MATCHED THEN
UPDATE
SET categories = s.category
WHEN NOT MATCHED THEN
INSERT (ID, title, categories)
VALUES (s.ID, s.title, s.category)
;
db<>fiddle
I wouldn't necessarily recommend this as a general solution though, because it appears you actually have other normalization problems to sort out first. You should really have separate tables for all this information:
Movie
Category
MovieCategory
I am querying a Microsoft SQL Server 2012.
The primary table (T1) structure contains account details:
AccountID, Name, Address
This table is dropped and recreated using external data nightly. We need to display this information but also need to exclude some of the records. Since we have no access to the external data we can't just add a column.
So we created a table (T2) to mark all the accounts we would like to exclude. It just has 2 fields:
AccountNo, Type
So we populated T2 and for every account we wanted to exclude from the display we gave the Type field a value of 'ex' (for exclude). We have no entries for the account we want to display.
When I execute the following query:
select T1.AccountID as acct, T1.Name as name, T1.Address as add
from T1
left join T2 on T1.AccountID = T2.AccountNo
WHERE T2.Type != 'ex'
The above query returns and empty set.
If I run a query to look for the value 'ex' (remove the !):
select T1.AccountID as acct, T1.Name as name, T1.Address as add
from T1
left join T2 on T1.AccountID = T2.AccountNo
WHERE T2.Type = 'ex'
The query returns the rows with that field populated with 'ex', as you expect.
I can search for NULL or NOT null with success but we need to use this extra table to do some other data manipulation in the future. In other words, we will not just be populating this field with "ex".
I'm wondering why I can't query the field in the joined table by looking for a Boolean false for a string. Is is because since the column doesn't exist in the table that is joined (T2) that it doesn't actually exist in the data set?
If that's the case how would I execute a query to return the records that do not equal a value in the joined table, whether that record exists in the joined table or not.
You can use the ISNULL solution like mentioned in the comments.
Another way you could write the query is this:
SELECT #t1.AccountID AS acct, #t1.Name AS [name], #t1.Address AS [add]
FROM #t1
LEFT JOIN #t2 ON #t1.AccountID = #t2.AccountNo
AND #t2.type = 'ex' --In case you add additional types to #t2
WHERE #t2.AccountNo IS NULL;
I'm trying to update a column in one table (#TEMPTABLE) using data in another table (#PEOPLE) by using the REPLACE() function.
#TEMPTABLE has a column called "NameString' that is a long string with a user's name and ID.
#PEOPLE has a column for ID, and IDnumber.
UPDATE #TEMPTABLE
SET NAMEString = REPLACE(NAMEString, a.[ID], a.[IDNumber]) FROM #PEOPLE a
I'm trying to replace all the ID's in the NameString Column with the IDnumbers coming from #People table.
You need to give it a join criterion. For example:
update #TEMPTABLE
set NAMEString = replace(a.NAMEString, a.ID, b.IDNumber)
from #TEMPTABLE a
left join #PEOPLE b
on a.id = b.ID
Also, make sure to reference the right table when you use the IDNumber column - your original query doesn't actually use the table containing IDNumber at all, as far as I can tell from your description of your tables.
Note that my example assumes there's an ID field in #TempTable, or something else to join on - otherwise, you may need to extract it from the NameString column first.
I have two tables. A column named CardName is in first table. There is duplicate data in this columns. That column also exists in second table. There is a column named amount related to each cardName also in second table. What i want is to select distinct CardName from 1st table and and take sum of all the amounts from second column whose cardname is in first table. BUT first table cardname should be distinct.
what should i do?
select name,sum(amount) from tableB
where name in (select distinct name from TableA)
group by name
use distinct keyword. Distinct will give you only the unique name from TableA and from the sub query result we are getting name and sum from tableB
Refer this : http://technet.microsoft.com/en-us/library/ms187831(v=sql.105).aspx
From you comment below UPDATE
with cte (name) as
(
select distict name from TableA
)
select cte.name,ISNULL(sum(count),0) from TableB as B
left join cte.name = B.name
The results of a union select statement in SQL Server 2008 is including records that are not found in either source table. Example:
theid is an integer ID value within each source table. Neither table includes theid value of 277741.
Select *
From DataTable1
WHere theid = 277741
-- 0 records returned
Select *
From DataTable2
Where theid = 277741
-- 0 records returned
However, when you run the Union Select statement below, a record is generated for theid.
Select *
Into ConjoinedData
From DataTable1
Union
Select *
From DataTable2
Where theid Not In (Select theid From DataTable1)
Select
From ConjoinedData
Where theid = 27741
-- 1 record returned
The theid field is not an identity field in either source table. Ultimately, the data for DataTable1 and DataTable2 came from the same parent, whose content includes an unrelated record with ID 277741. However, there are no foreign key relationships to it or any other table on either of the source tables. I have tried changing to a Union All query with no success. I have created an index on theid in both source tables and the 'created' record appears. I have dropped and recreated the source tables numerous times to no avail. Why is SQL Server getting the unrelated record from the disconnected parent table (source talbes were both cereated from the same parent using Select..Into statements and no foreign key relationship to either table back to the parent)?
277741 is different from 27741. The following script reproduces exactly what you describe:
create table Table1 (id int);
create table Table2 (id int);
go
insert into Table1(id) values (277742);
insert into Table2(id) values (27741);
go
Select * From Table1 WHere id = 277741;
Select * From Table2 Where id = 277741;
go
Select *
Into ConjoinedData
From Table1
Union
Select *
From Table2
Where id Not In (Select id From Table1);
Select *
From ConjoinedData
Where id = 27741;