Loop through each column name from one table and insert that name into another table? - sql

I have two tables. One table has a list of 500 columns. Another table references each column name like this
Select Top 1 * from MyReferenceTable
Which returns the results
(69, 'FirtName', 1, NULL)
(69, 'LastName', 2, NULL)
Where 'FirstName' is the name of the column from an actual table.
So I want to fill this reference table with the column names from the other table as so
Insert Into MyReferenceTable
FileId, ColumnName1, ColumnOrder, DefaultValue
Values(69, Select ColumnName From OtherTable? ,
Select Next Sequential Identity?, NULL)
My issue is how can I loop through the other table get the column name for each row, also insert an identity in sequentialOrder as ColumnOrder?
Typing out that insert statement manually for over 500 columns would take many moons.

This is a terrible idea, but the answer to your question is straight-forward:
INSERT INTO MyReferenceTabel (FileId, ColumnName1, ColumnOrder, DefaultValue)
SELECT 69, [name], [column_id], NULL
FROM sys.columns
WHERE [object_id] = OBJECT_ID('MyOtherTable')
Basically you craft a SELECT statement that returns the values you want, and then just add the INSERT statement over it.
But again, this smells of a terrible design choice that will bite you in the end. But it's still good to know how to get this information, so I'm posting this example here.

Related

SQL, Hive select columns with same values and create new table

I have one table with two columns - Search & Affiliate but some of the values duplicated between both.
Ex: Search 123, 345, 567, 768, 008
Affiliate 425, 345, 986, 008
I want to take the ones present in both (008, 345) + all the other ones in Affiliate and create a separate table, called unique affiliate. The remaining ones in Search is also what I want to convert into another separate table called unique search.
I can create two tables separately, join common values and create a table but how do I include the rest as well with the join? Or maybe pick common values from both and create a new table but then again, what about the rest of the values in each field?
All the affiliates can be found by a simple select distinct from the Affiliate column.
The search can be found by selecting all the Search items that are NOT in the list of Search items that occur in the Affiliate column.
To get the Search items that occur in the affiliate column use an inner join sub query to select them.
Then do a SELECT on the Search column where the items are not in the list generated by the sub query
--INSERT INTO your new affiliates_table
SELECT DISTINCT Affiliate
FROM tbl_SearchAffiliate
WHERE ISNULL(Affiliate,'') <> ''
--INSERT INTO your new search_table
SELECT DISTINCT Search
FROM tbl_SearchAffiliate
WHERE Search NOT IN
( --select the search values that occur in the affilliates column
SELECT x.Search
FROM tbl_SearchAffiliate x
INNER JOIN tbl_SearchAffiliate y ON x.Search = y.Affiliate
)
AND ISNULL(Search,'') <> ''
/********************
below is the data I assumed from your question
CREATE TABLE [dbo].[tbl_SearchAffiliate](
[Search] [nvarchar](50) NULL,
[Affiliate] [nvarchar](50) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[tbl_SearchAffiliate] ([Search], [Affiliate]) VALUES (N'123', N'425')
GO
INSERT [dbo].[tbl_SearchAffiliate] ([Search], [Affiliate]) VALUES (N'345', N'345')
GO
INSERT [dbo].[tbl_SearchAffiliate] ([Search], [Affiliate]) VALUES (N'567', N'986')
GO
INSERT [dbo].[tbl_SearchAffiliate] ([Search], [Affiliate]) VALUES (N'768', N'008')
GO
INSERT [dbo].[tbl_SearchAffiliate] ([Search], [Affiliate]) VALUES (N'008', NULL)
GO
*******************/

INSERT INTO EXCEPT using only 2 identify columns

hopefully this is an easy one for you folk smarter than me. I am trying to perform an insert into a table from another matching table, but I only want to insert if the row doesn't already exist. Some of these values in the row if it exists may be changed. Which is okay.
I'm thinking if two of the columns match upon insert, then don't insert and leave record as is. If those two columns don't match then insert the row. I have looked through merge, and also INSERT INTO EXCEPT. This code will work: but it is not what I need.
INSERT INTO LotDetail
SELECT UID, LotKey, SerialNo, TypeID, HotWeight, YieldGradKey, PeltGrade,
WeightRange, MarketValue, PremiumDiscount, PeltValue, OffalValue,
PricingKey, USDAGrade, [Timestamp] FROM LotDetail
EXCEPT
SELECT UID, LotKey, SerialNo, TypeID, HotWeight, YieldGradKey, PeltGrade,
WeightRange, MarketValue, PremiumDiscount, PeltValue, OffalValue,
PricingKey, USDAGrade, [Timestamp] FROM LotDetail_STAGING
The problem with the above code is that I must match all columns otherwise it tells me the table definition doesn't match. I only want to timestamp and serialno as the identifiers. I don't want to match on the other fields as they may change.
The problem is that if the record exists on the LotDetail table already and the 'hotweight' or 'marketvalue' have changed, I want to preserve those changes and not overwrite the record. I am simply looking to insert ONLY when 'serialno' and 'timestamp' don't exist. Those fields cannot be changed. Any thoughts?
Hmmm, I think you have your tables backwards. It makes more sense to me to insert from the "staging" table into the final table.
Then, you can use NOT EXISTS instead of EXCEPT:
INSERT INTO LotDetail(UID, LotKey, SerialNo, TypeID, HotWeight, YieldGradKey, PeltGrade,
WeightRange, MarketValue, PremiumDiscount, PeltValue, OffalValue,
PricingKey, USDAGrade, [Timestamp]
)
SELECT UID, LotKey, SerialNo, TypeID, HotWeight, YieldGradKey, PeltGrade,
WeightRange, MarketValue, PremiumDiscount, PeltValue, OffalValue,
PricingKey, USDAGrade, [Timestamp]
FROM LotDetail_STAGING ls
WHERE NOT EXISTS (SELECT 1
FROM LotDetail l
WHERE l.SerialNo = ls.serialNo AND
l.[Timestamp] = ls.[Timestamp]
);
I also think it is a good idea to list the columns when doing an INSERT.

SQL Server where condition on column with separated values

I have a table with a column that can have values separated by ",".
Example column group:
id column group:
1 10,20,30
2 280
3 20
I want to create a SELECT with where condition on column group where I can search for example 20 ad It should return 1 and 3 rows or search by 20,280 and it should return 1 and 2 rows.
Can you help me please?
As pointed out in comments,storing mutiple values in a single row is not a good idea..
coming to your question,you can use one of the split string functions from here to split comma separated values into a table and then query them..
create table #temp
(
id int,
columnss varchar(100)
)
insert into #temp
values
(1,'10,20,30'),
(2, '280'),
(3, '20')
select *
from #temp
cross apply
(
select * from dbo.SplitStrings_Numbers(columnss,',')
)b
where item in (20)
id columnss Item
1 10,20,30 20
3 20 20
The short answer is: don't do it.
Instead normalize your tables to at least 3NF. If you don't know what database normalization is, you need to do some reading.
If you absolutely have to do it (e.g. this is a legacy system and you cannot change the table structure), there are several articles on string splitting with TSQL and at least a couple that have done extensive benchmarks on various methods available (e.g. see: http://sqlperformance.com/2012/07/t-sql-queries/split-strings)
Since you only want to search, you don't really need to split the strings, so you can write something like:
SELECT id, list
FROM t
WHERE ','+list+',' LIKE '%,'+#searchValue+',%'
Where t(id int, list varchar(max)) is the table to search and #searchValue is the value you are looking for. If you need to search for more than one value you have to add those in a table and use a join or subquery.
E.g. if s(searchValue varchar(max)) is the table of values to search then:
SELECT distinct t.id, t.list
FROM t INNER JOIN s
ON ','+t.list+',' LIKE '%,'+s.searchValue+',%'
If you need to pass those search values from ADO.Net consider table parameters.

Inserting SCOPE_IDENTITY() into a junction table

Consider the following little script:
create table #test
(testId int identity
,testColumn varchar(50)
)
go
create table #testJunction
(testId int
,otherId int
)
insert into #test
select 'test data'
insert into #testJunction(testId,otherId)
select SCOPE_IDENTITY(),(select top 10 OtherId from OtherTable)
--The second query here signifies some business logic to resolve a many-to-many
--fails
This, however, will work:
insert into #test
select 'test data'
insert into #testJunction(otherId,testId)
select top 10 OtherId ,(select SCOPE_IDENTITY())
from OtherTable
--insert order of columns is switched in #testJunction
--SCOPE_IDENTITY() repeated for each OtherId
The second solution works and all is well. I know it doesn't matter, but for continuity's sake I like having the insert done in the order in which the columns are present in the database table. How can I acheieve that? The following attempt gives a subquery returned more than 1 value error
insert into #test
select 'test data'
insert into #testJunction(otherId,testId)
values ((select SCOPE_IDENTITY()),(select top 10 drugId from Drugs))
EDIT:
On a webpage a new row is entered into a table with a structure like
QuizId,StudentId,DateTaken
(QuizId is an identity column)
I have another table with Quiz Questions like
QuestionId,Question,CorrectAnswer
Any number of quizzes can have any number of questions, so in this example testJunction
resolves that many to many. Ergo, I need the SCOPE_IDENTITY repeated for however many questions are on the quiz.
The version that fails
insert into #testJunction(testId,otherId)
select SCOPE_IDENTITY(),(select top 10 OtherId from OtherTable)
will insert one row with scope_identity() in the first column and a set of 10 values in the second column. A column can not have sets so that one fails.
The one that works
insert into #testJunction(otherId,testId)
select top 10 OtherId ,(select SCOPE_IDENTITY())
from OtherTable
will insert 10 rows from OtherTable with OtherId in the first column and the scalar value of scope_identity() in the second column.
If you need to switch places of the columns it would look like this instead.
insert into #testJunction(testId,otherId)
select top 10 SCOPE_IDENTITY(), OtherId
from OtherTable
You need the output clause. Look it up in BOL.
Try this way:
Declare #Var int
insert into #test
select 'test data'
select #var=scope_identity()
insert into #testJunction(otherId,testId)
select top 10 #var,drugId from Drugs

Add rows to a table then loop back and add more rows for a different userid

I have a table with 4 columns - ID, ClubID, FitnessTestNameID and DisplayName
I have another table called Club and it has ID and Name
I want to add two rows of data to the 1st table for each club
I can write a statement like this, but can someone tell me how to create a loop so that I can insert the two rows, set the #clubid + 1 and then loop back again?
declare #clubid int
set #clubid = 1
insert FitnessTestsByClub (ClubID,FitnessTestNameID,DisplayName)
values (#clubid,'1','Height (cm)')
insert FitnessTestsByClub (ClubID,FitnessTestNameID,DisplayName)
values (#clubid,'2','Weight (kg)')
You can probably do this with one statement only. No need for loops:
INSERT INTO FitnessTestsByClub
(ClubID, FitnessTestNameID, DisplayName)
SELECT
c.ID, v.FitnessTestNameID, v.DisplayName
FROM
Club AS c
CROSS JOIN
( VALUES
(1, 'Height (cm)'),
(2, 'Weight (kg)')
) AS v (FitnessTestNameID, DisplayName)
WHERE
NOT EXISTS -- a condition so no duplicates
( SELECT * -- are inserted
FROM FitnessTestsByClub AS f -- and the statement can be run again
WHERE f.ClubID = c.ID -- in the future, when more clubs
) -- have been added.
;
The Table Value Constructor syntax above (the (VALUES ...) construction) is valid from version 2008 and later.
There is a nice article with lots of useful examples of how to use them, by Robert Sheldon: Table Value Constructors in SQL Server 2008