INSERT INTO With a SubQuery and some operations - sql

I'm trying to insert some data to a table contains two things : "a string" and "maximum number in Order column + 1".
This is my query:
INSERT INTO MyTable ([Text],[Order])
SELECT 'MyText' , (Max([Order]) + 1)
FROM MyTable
What is going wrong with my query?
I'm using Microsoft SQL Server 2005 SP3.

You can test this query like this:
I don't receive error:
create table #MyTable
(
[Text] varchar(40),
[Order] int NOT NULL
)
INSERT INTO #MyTable([Text],[Order])
SELECT 'MyText' [Text], isnull(max([order]) + 1, 0) [Order]
FROM #MyTable
drop table #MyTable
Original:
INSERT INTO MyTable ([Text],[Order])
SELECT 'MyText' [Text], max([Order]) + 1 [Order]
FROM MyTable
or
INSERT INTO MyTable ([Text],[Order])
SELECT top 1 'MyText' [Text], max([Order]) + 1 [Order]
FROM MyTable
limit is not valid in SQL Server as far as I know.

Cannot insert the value NULL into column 'Order', table 'master.dbo.MyTable'; column does not allow nulls. INSERT fails. The statement has been terminated.
This means that the Order column isn't allowed to be null, and that the Max([Order]) + 1 part of your column returns NULL.
This is because your table is empty, as you already noticed by yourself.
You can work around this by replacing NULL by a real number in the query, using ISNULL():
INSERT INTO MyTable ([Text],[Order])
SELECT 'MyText' , (isnull(Max([Order]),0) + 1)
FROM MyTable

Unless he has a column named OrderBy
then he would have to add / assign all values within that Insert especially if the column does not allow for nulls
sounds like fully qualifying the Insert with the dbo.MyTable.Field may make more sense.
also why are you naming fields with SQL Key words...???
INSERT INTO MyTable ([Text],[Order] Values('MyTextTest',1)
try a test insert first..

Related

Tally Table in SQL

I want to create a bunch of data with Tally table in SQL (sql2008) and definitely need help.
First of all, I have this table which contains 2 columns.
{
AcctNum (nchar(30), null),
DataInfo (nchar(745), null)
}
While I don't care the data in the DataInfo column, I do want to add about 10k of row into the table with unique AcctNum on each row.
The problem though is I need to keep the length of the data in both column. For example, AcctNum column looks like "400000000000001 ". how do I increment the number while keep the "blank space"?
Not sure if I make much sense here, but please let me know and I will try to explain more, thanks!
Using a recursive common table expression :
-- set up a table variable for demo purpose
declare #t table (AcctNum nchar(30) null, DataInfo nchar(745) null);
-- insert the starting value
insert #t values ('400000000000001', null);
-- run the cte to generate the sequence
with cte (acctnum, num) as (
select acctnum, cast(acctnum as bigint) + 1 num -- starting value
from #t
union all
select acctnum, num+1 from cte
where num < cast(acctnum as bigint) + 10000 -- stopping value
)
-- insert data sequence into the table
insert #t (AcctNum, DataInfo)
select num, null from cte
option (maxrecursion 10000);
select * from #t;
The table variable #t will now contain acctnum 400000000000001 -> 400000000010001 as a contiguous sequence.

Get the wrong line ID in ms sql

I have an INSERT statment wich inserts large amount of data into tableA from tableB.
Here is a very simple code example:
INSERT [dbo].[tableA]
SELECT field1 [field_1]
FROM [dbo].[tableB]
WHERE [codeID] IN (SELECT [codeID] FROM #tempTable WHERE RecordMarker = 1)
There is a temporary table wich holds codeIDs (at least 1 or more) needed to insert to tableA.
But there would be incorrent data in tableB what cannot be inserted into tableA. For example an numberic(30,2) field cannot map to numeric(13,2). In this case I get an excetpion and the statement has been terminated.
How can I get the CodeID or the wrong line number in tableB if I get an error? Now I have just the error message but no line number.
For example:
Msg 8115, Level 16, State 8, Line 1
Arithmetic overflow error converting numeric to data type numeric.
The statement has been terminated.
EDIT: There are more than one field in the table with different field types. So the numeric type is just an example.
Please try the following:
INSERT [dbo].[tableA]
SELECT field1 [field_1]
FROM [dbo].[tableB]
WHERE [codeID] IN (SELECT [codeID] FROM #tempTable WHERE RecordMarker = 1)
AND [codeID] <= 9999999999999.99;
INSERT ErrorLog
SELECT *
FROM [dbo].[tableB]
WHERE [codeID] > 9999999999999.99;
If you know the type of the destination field you're having the issue with, in this case a numeric of (13,2) precision, you can run a SELECT with a TRY_CONVERT on the potential problem field against your temp table and filter for NULL results. You could add a WHERE clause to your insert statement if you wanted to ensure that it would run successfully and not try to insert those "bad" rows.
CREATE TABLE #t (x NUMERIC(30,2),field2 varchar(10))
INSERT INTO #t
SELECT 123456789.23,'x'
UNION
SELECT 12345678901212343.23,'y'
UNION
SELECT 12345678923523523235.23,'z'
UNION
SELECT 42.0, 'a'
SELECT *, TRY_CONVERT(NUMERIC(13,2),x,1) [Converted to numeric(13,2)] FROM #t
Reference: http://msdn.microsoft.com/en-us/library/hh230993.aspx

How do I return the column name in table where a null value exists?

I have a table of more than 2 million rows and over 100 columns. I need to run a query that checks if there are any null values in any row or column of the table and return an ID number where there is a null. I've thought about doing the following, but I was wondering if there is a more concise way of checking this?
SELECT [ID]
from [TABLE_NAME]
where
[COLUMN_1] is null
or [COLUMN_2] is null
or [COLUMN_3] is null or etc.
Your method is fine. If your challenge is writing out the where statement, then you can run a query like this:
select column_name+' is null or '
from information_schema.columns c
where c.table_name = 'table_name'
Then copy the results into a query window and use them for building the query.
I used SQL Server syntax for the query, because it looks like you are using SQL Server. Most databases support the INFORMATION_SCHEMA tables, but the syntax for string concatenation varies among databases. Remember to remove the final or at the end of the last comparison.
You can also copy the column list into Excel and use Excel formulas to create the list.
You can use something similar to the following:
declare #T table
(
ID int,
Name varchar(10),
Age int,
City varchar(10),
Zip varchar(10)
)
insert into #T values
(1, 'Alex', 32, 'Miami', NULL),
(2, NULL, 24, NULL, NULL)
;with xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' as ns)
select ID,
(
select *
from #T as T2
where T1.ID = T2.ID
for xml path('row'), elements xsinil, type
).value('count(/row/*[#ns:nil = "true"])', 'int') as NullCount
from #T as T1

Select records with order of IN clause

I have
SELECT * FROM Table1 WHERE Col1 IN(4,2,6)
I want to select and return the records with the specified order which i indicate in the IN clause
(first display record with Col1=4, Col1=2, ...)
I can use
SELECT * FROM Table1 WHERE Col1 = 4
UNION ALL
SELECT * FROM Table1 WHERE Col1 = 6 , .....
but I don't want to use that, cause I want to use it as a stored procedure and not auto generated.
I know it's a bit late but the best way would be
SELECT *
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')
Or
SELECT CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')s_order,
*
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY s_order
You have a couple of options. Simplest may be to put the IN parameters (they are parameters, right) in a separate table in the order you receive them, and ORDER BY that table.
The solution is along this line:
SELECT * FROM Table1
WHERE Col1 IN(4,2,6)
ORDER BY
CASE Col1
WHEN 4 THEN 1
WHEN 2 THEN 2
WHEN 6 THEN 3
END
select top 0 0 'in', 0 'order' into #i
insert into #i values(4,1)
insert into #i values(2,2)
insert into #i values(6,3)
select t.* from Table1 t inner join #i i on t.[in]=t.[col1] order by i.[order]
Replace the IN values with a table, including a column for sort order to used in the query (and be sure to expose the sort order to the calling application):
WITH OtherTable (Col1, sort_seq)
AS
(
SELECT Col1, sort_seq
FROM (
VALUES (4, 1),
(2, 2),
(6, 3)
) AS OtherTable (Col1, sort_seq)
)
SELECT T1.Col1, O1.sort_seq
FROM Table1 AS T1
INNER JOIN OtherTable AS O1
ON T1.Col1 = O1.Col1
ORDER
BY sort_seq;
In your stored proc, rather than a CTE, split the values into table (a scratch base table, temp table, function that returns a table, etc) with the sort column populated as appropriate.
I have found another solution. It's similar to the answer from onedaywhen, but it's a little shorter.
SELECT sort.n, Table1.Col1
FROM (VALUES (4), (2), (6)) AS sort(n)
JOIN Table1
ON Table1.Col1 = sort.n
I am thinking about this problem two different ways because I can't decide if this is a programming problem or a data architecture problem. Check out the code below incorporating "famous" TV animals. Let's say that we are tracking dolphins, horses, bears, dogs and orangutans. We want to return only the horses, bears, and dogs in our query and we want bears to sort ahead of horses to sort ahead of dogs. I have a personal preference to look at this as an architecture problem, but can wrap my head around looking at it as a programming problem. Let me know if you have questions.
CREATE TABLE #AnimalType (
AnimalTypeId INT NOT NULL PRIMARY KEY
, AnimalType VARCHAR(50) NOT NULL
, SortOrder INT NOT NULL)
INSERT INTO #AnimalType VALUES (1,'Dolphin',5)
INSERT INTO #AnimalType VALUES (2,'Horse',2)
INSERT INTO #AnimalType VALUES (3,'Bear',1)
INSERT INTO #AnimalType VALUES (4,'Dog',4)
INSERT INTO #AnimalType VALUES (5,'Orangutan',3)
CREATE TABLE #Actor (
ActorId INT NOT NULL PRIMARY KEY
, ActorName VARCHAR(50) NOT NULL
, AnimalTypeId INT NOT NULL)
INSERT INTO #Actor VALUES (1,'Benji',4)
INSERT INTO #Actor VALUES (2,'Lassie',4)
INSERT INTO #Actor VALUES (3,'Rin Tin Tin',4)
INSERT INTO #Actor VALUES (4,'Gentle Ben',3)
INSERT INTO #Actor VALUES (5,'Trigger',2)
INSERT INTO #Actor VALUES (6,'Flipper',1)
INSERT INTO #Actor VALUES (7,'CJ',5)
INSERT INTO #Actor VALUES (8,'Mr. Ed',2)
INSERT INTO #Actor VALUES (9,'Tiger',4)
/* If you believe this is a programming problem then this code works */
SELECT *
FROM #Actor a
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY case when a.AnimalTypeId = 3 then 1
when a.AnimalTypeId = 2 then 2
when a.AnimalTypeId = 4 then 3 end
/* If you believe that this is a data architecture problem then this code works */
SELECT *
FROM #Actor a
JOIN #AnimalType at ON a.AnimalTypeId = at.AnimalTypeId
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY at.SortOrder
DROP TABLE #Actor
DROP TABLE #AnimalType
ORDER BY CHARINDEX(','+convert(varchar,status)+',' ,
',rejected,active,submitted,approved,')
Just put a comma before and after a string in which you are finding the substring index or you can say that second parameter.
And first parameter of CHARINDEX is also surrounded by , (comma).

How can I insert random values into a SQL Server table?

I'm trying to randomly insert values from a list of pre-defined values into a table for testing. I tried using the solution found on this StackOverflow question:
stackoverflow.com/.../update-sql-table-with-random-value-from-other-table
When I I tried this, all of my "random" values that are inserted are exactly the same for all 3000 records.
When I run the part of the query that actually selects the random row, it does select a random record every time I run it by hand, so I know the query works. My best guesses as to what is happening are:
SQL Server is optimizing the SELECT somehow, not allowing the subquery to be evaluated more than once
The random value's seed is the same on every record the query updates
I'm stuck on what my options are. Am I doing something wrong, or is there another way I should be doing this?
This is the code I'm using:
DECLARE #randomStuff TABLE ([id] INT, [val] VARCHAR(100))
INSERT INTO #randomStuff ([id], [val])
VALUES ( 1, 'Test Value 1' )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 2, 'Test Value 2' )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 3, 'Test Value 3' )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 4, 'Test Value 4' )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 5, 'Test Value 5' )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 6, null )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 7, null )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 8, null )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 9, null )
INSERT INTO #randomStuff ([id], [val])
VALUES ( 10, null )
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM #randomStuff ORDER BY NEWID())
When the query engine sees this...
(SELECT TOP 1 [val] FROM #randomStuff ORDER BY NEWID())
... it's all like, "ooooh, a cachable scalar subquery, I'm gonna cache that!"
You need to trick the query engine into thinking it's non-cachable. jfar's answer was close, but the query engine was smart enough to see the tautalogy of MyTable.MyColumn = MyTable.MyColumn, but it ain't smart enough to see through this.
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 val
FROM #randomStuff r
INNER JOIN MyTable _MT
ON M.Id = _MT.Id
ORDER BY NEWID())
FROM MyTable M
By bringing in the outer table (MT) into the subquery, the query engine assumes subquery will need to be re-evaluated. Anything will work really, but I went with the (assumed) primary key of MyTable.Id since it'd be indexed and would add very little overhead.
A cursor would probably be just as fast, but is most certainly not as fun.
use a cross join to generate random data
I've had a play with this, and found a rather hacky way to do it with the use of an intermediate table variable.
Once #randomStuff is set up, we do this (note in my case, #MyTable is a table variable, adjust accordingly for your normal table):
DECLARE #randomMappings TABLE (id INT, val VARCHAR(100), sorter UNIQUEIDENTIFIER)
INSERT INTO #randomMappings
SELECT M.id, val, NEWID() AS sort
FROM #MyTable AS M
CROSS JOIN #randomstuff
so at this point, we have an intermediate table with every combination of (mytable id, random value), and a random sort value for each row specific to that combination. Then
DELETE others FROM #randomMappings AS others
INNER JOIN #randomMappings AS lower
ON (lower.id = others.id) AND (lower.sorter < others.sorter)
This is an old trick which deletes all rows for a given MyTable.id except for the one with the lower sort value -- join the table to itself where the value is smaller, and delete any where such a join succeeded. This just leaves behind the lowest value. So for each MyTable.id, we just have one (random) value left.. Then we just plug it back into the table:
UPDATE #MyTable
SET MyColumn = random.val
FROM #MyTable m, #randomMappings AS random
WHERE (random.id = m.id)
And you're done!
I said it was hacky...
I don't have time to check this right now, but my gut tells me that if you were to create a function on the server to get the random value that it would not optimize it out.
then you would have
UPDATE MyTable
Set MyColumn = dbo.RANDOM_VALUE()
There is no optimization going on here.
Your using a subquery that selects a single value, there is nothing to optimize.
You can also try putting a column from the table your updating in the select and see if that changes anything. That may trigger an evaluation for every row in MyTable
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM #randomStuff ORDER BY NEWID()
WHERE MyTable.MyColumn = MyTable.MyColumn )
I came up with a solution which is a bit of a hack and very inefficient (10~ seconds to update 3000 records). Because this is being used to generate test data, I don't have to be concerned about speed however.
In this solution, I iterate over every row in the table and update the values one row at a time. It seems to work:
DECLARE #rows INT
DECLARE #currentRow INT
SELECT #rows = COUNT(*) FROM dbo.MyTable
SET #currentRow = 1
WHILE #currentRow < #rows
BEGIN
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM #randomStuff ORDER BY NEWID())
WHERE MyPrimaryKey = (SELECT b.MyPrimaryKey
FROM(SELECT a.MyPrimaryKey, ROW_NUMBER() OVER (ORDER BY MyPrimaryKey) AS rownumber
FROM MyTable a) AS b
WHERE #currentRow = b.rownumber
)
SET #currentRow = #currentRow + 1
END