Says I have this t-sql command :
Insert into x(a,b) select a,b from y
While x contains 10 records, two of them will generate errors when inserted into y, like string should be truncated or numeric overflow. Now what I want is when the command is executed, only 8 records will be inserted into y, meaning that all error records will be ignored.
Is this possible?
cannot understand, why such requirement is there. solution is there, but still not satisfied with requirement or say not able to digest such scenario.
you can loop through each record one by one and if no error then insert.
try this
Set Nocount On;
Declare #Id Int
,#Total Int
,#Loop Int
,#a Varchar(5)
,#b Numeric(3,1)
If Object_Id('tempdb.dbo.#x') Is Not Null
Begin
Drop Table #x;
End
If Object_Id('tempdb.dbo.#y') Is Not Null
Begin
Drop Table #y;
End
Create Table #x
(
Id Int Identity(1,1) Primary Key
,a Varchar(5)
,b Numeric(3,1)
)
Create Table #y
(
Id Int Identity(1,1) Primary Key
,a Varchar(10)
,b Numeric(5,2)
)
Insert Into #y(a,b)
Values
('abcdef',200)
,('abc',12)
,('abfdef',260)
,('34c',16)
,('abwe',18)
,('asdc',29)
,('3fgc',17)
,('a45we',88)
,('a3d7',49)
,('a367',48)
Select #Total = Count(*)
,#Id = 0
,#Loop = 0
From #y With (Nolock)
While (#Loop < #Total)
Begin
Select Top 1
#Id = y.Id
,#a = Substring(y.a,0,5)
,#b = Cast(y.b As Numeric(3,1))
From #y As y With (Nolock)
Where y.Id > #Id
Order By y.Id Asc
If ##Error <> 0 Goto NextLevel
Insert Into #x
Select #a
,#b
Goto NextLevel
NextLevel:
Select #Loop = #Loop + 1
End
Select *
From #x With (Nolock)
Related
I am just learning to code SQL. Can someone help me with an update statement, I have done the insert but am stuck with an update. My table prime_test has two columns number and is_prime
Here is the question:
Write one or more update statements that sets the 'is_prime' column for each associated integer. For a prime, the column should read 'prime'. For non-primes, the column should read 'composite'.
My code
CREATE TABLE `sql_inventory`.`prime_test` (
`number` INT NOT NULL,
`is_prime` VARCHAR(50) NULL,
PRIMARY KEY (`number`));
INSERT INTO `prime`.`prime_test`
(`number`)
VALUES
(rand()*(100-2+1)+2);
Function to find the prime numbers:
CREATE FUNCTION isPrime(#num int)
RETURNS VARCHAR(50)
BEGIN
DECLARE #prime_or_notPrime INT
DECLARE #counter INT
DECLARE #retVal VARCHAR(50)
SET #retVal = 'composite'
SET #prime_or_notPrime = 1
SET #counter = 2
WHILE (#counter <= #number/2 )
BEGIN
IF (( #number % #counter) = 0 )
BEGIN
set #prime_or_notPrime = 0
BREAK
END
IF (#prime_or_notPrime = 1 )
BEGIN
SET #retVal = 'prime'
END
SET #counter = #counter + 1
END
return #retVal
END
update prime_test
set is_prime = dbo.isPrime(select number From 'prime'.'prime_test')
I'm using a query with two parameters (#campaign,#resultcode) to populate a table with 3 columns ("Campaignname","Disposition","Count"), but when either one of those parameters don't exist in the database, nothing populates in the table. Is there a way to make it populate the two parameters with a count of 0? Also I have it set so that multiple parameters can be selected. I've tried IIF(IsNothing()..., IIF(***.value = null or ""). Still doesn't do what I want it to do. Some help?
Included code from comment response:
SELECT databasename, callresultdescription, count(*) as Count
FROM bpsql00.[histCallCenterStats].[dbo].[CallResults]
WHERE databasename IN(#campaign) AND callresultcode IN(#resultcode)
GROUP BY databasename, callresultdescription
The callresultdescription is AKA disposition
You could union them together:
--create table [CallResults] (databasename varchar(10),callresultdescription
varchar(10),myvalue int)
--insert into [CallResults]
--values ('a','AA',1),
--('b','BB',2),
--('c','CC',3)
--select * from [CallResults]
declare #campaign varchar(10)='d',#resultcode varchar(10)='dd' ;
SELECT databasename, callresultdescription,
count(1) as [Count]
FROM [CallResults]
WHERE databasename IN (#campaign)
AND callresultdescription IN (#resultcode)
GROUP BY databasename, callresultdescription
UNION
SELECT databasename=#campaign,
callresultdescription=#resultcode,
0 as [Count]
from [CallResults]
where databasename not IN (#campaign)
AND callresultdescription not IN (#resultcode)
You can accomplish this with an IF statement in the SQL query:
IF EXISTS (SELECT 1 FROM bpsql00.[histCallCenterStats].[dbo].[CallResults] WHERE databasename IN ( #campaign ) AND callresultcode IN ( #resultcode ))
SELECT databasename
, callresultdescription
, [Count] = COUNT(*)
FROM bpsql00.[histCallCenterStats].[dbo].[CallResults]
WHERE databasename IN ( #campaign )
AND callresultcode IN ( #resultcode )
GROUP BY databasename ,
callresultdescription;
ELSE
SELECT databasename = #campaign
, callresultdescription = #resultcode
, [Count] = 0
Edit per question in the comment:
It gets tricky when you need to return a multi-valued parameter. If you're on SQL 2016, you can use the new TSQL STRING_SPLIT function to split out their comma-separated selections. There are also splitter functions you can find on the interwebs for prior versions of SQL. The simplest solution, though, is to let the query return nothing and set the NoRowsMessage of the tablix to inform the client. You can use an expression like
="No records found in the selected campaigns (" & _
Parameters!campaign.Value & ") and result codes (" & _
Parameters!resultcode.Value & ")."
That gives the user a record of what was searched and that nothing was found to match their criteria.
So finally figured it out. I have concluded that the program is limited what I wanted to do. So... why not let SQL do it for me and I can just call a stored procedure. BINGO. I had to create a function as well. So for anyone who needs something like this.
Stored procedure I created:
alter procedure [dbo].[rs_Query]
#campaign varchar (100),
#resultcode varchar (100)
as
Begin
declare #var_campaign varchar(100)
declare #var_resultcode varchar(100)
declare #c table(ID int identity, databasename varchar(100))
declare #r table(ID int identity, callresultcode varchar(100))
insert into #c select element from dbo.func_split(#campaign, ',')
insert into #r select element from dbo.func_split(#resultcode,',')
declare #dbcnt int --count of campaigns selected
declare #crcnt int --count of dispositions selected
declare #crrow int --row id for campaigns selected
declare #dbrow int --row id for dispositions selected
declare #tempdbname varchar(50) --temp campaign name
declare #tempcr varchar(50) --temp call result name
declare #t table (databasename varchar(100), callresultdescription varchar (100), Count int)
declare #count int
select #dbcnt = count(*) from #c
select #crcnt = count(*) from #r
select #dbrow = 1
select #crrow = 1
while #dbcnt >= #dbrow
begin
set #tempdbname = (select databasename
from bpsql00.callcenteraux.dbo.DailyReportsCampaign
where databasename = (select databasename from #c where id = #dbrow))
set #crrow = 1
while #crcnt >= #crrow
begin
set #tempcr = (select CallResultDescription
from CallResultCode
where CallResultCode = (select CallResultCode from #r where id = #crrow));
if exists(select 1 from bpsql00.[histCallCenterStats].[dbo].[CallResults]
where CallResultCode = (select CallResultCode from #r where id = #crrow) and databasename = #tempdbname)
begin
select #count = count(*) from bpsql00.[histCallCenterStats].[dbo].[CallResults]
where CallResultCode = (select CallResultCode from #r where id = #crrow) and databasename = #tempdbname
insert into #t values(#tempdbname,#tempcr,#count)
end
else
begin
insert into #t values(#tempdbname,#tempcr,0)
end
set #crrow = #crrow + 1
end
set #dbrow = #dbrow + 1
end
select * from #t
end
And function I created:
ALTER FUNCTION [dbo].[func_Split]
(
#DelimitedString varchar(8000),
#Delimiter varchar(100)
)
RETURNS #tblArray TABLE
(
ElementID int IDENTITY(1,1), -- Array index
Element varchar(1000) -- Array element contents
)
AS
BEGIN
-- Local Variable Declarations
-- ---------------------------
DECLARE #Index smallint,
#Start smallint,
#DelSize smallint
SET #DelSize = LEN(#Delimiter + 'x') - 1
-- Loop through source string and add elements to destination table array
-- ----------------------------------------------------------------------
WHILE LEN(#DelimitedString) > 0
BEGIN
SET #Index = CHARINDEX(#Delimiter, #DelimitedString)
IF #Index = 0
BEGIN
INSERT INTO
#tblArray
(Element)
VALUES
(LTRIM(RTRIM(#DelimitedString)))
BREAK
END
ELSE
BEGIN
INSERT INTO
#tblArray
(Element)
VALUES
(LTRIM(RTRIM(SUBSTRING(#DelimitedString, 1,#Index - 1))))
SET #Start = #Index + #DelSize
SET #DelimitedString = SUBSTRING(#DelimitedString, #Start , LEN(#DelimitedString) - #Start + 1)
END
END
RETURN
END
i have a stored procedure that searches like bellow:
BEGIN
#At first, Search in name of job:
(SELECT * FROM tb_job WHERE `name` LIKE '%some%' AND `name` LIKE '%thing%')
UNION
# second, search for tags:
(SELECT * FROM tb_job WHERE id IN
(
SELECT idJob FROM
(
(SELECT 2 AS priority1, COUNT(tb_job_tag.idTag) AS priority2, idJob FROM tb_job_tag WHERE idTag IN
(SELECT tb_tag.id FROM tb_tag WHERE tag LIKE '%some%' OR tag LIKE '%thing%')
GROUP BY tb_job_tag.idJob)
UNION
(SELECT 1, COUNT(tb_job_tag.idTag), idJob FROM tb_job_tag WHERE idTag IN
(SELECT tb_tag.id FROM tb_tag WHERE tag LIKE '%some%' AND tag LIKE '%thing%')
GROUP BY tb_job_tag.idJob)
)
AS t ORDER BY priority1, priority2 DESC
)
)
END
now i have 2 questions: how can i pass an array of words and separate them in mysql and use them in LIKE? second, how can i make this search better?
(i have 3table: tb_job, tb_tag, tb_job_tag that stores job's id and tag's id). thanks for your help.
/**
* http://www.aspdotnet-suresh.com/2013/07/sql-server-split-function-example-in.html
*/
CREATE FUNCTION dbo.Array(#String nvarchar(4000), #Delimiter char(1))
RETURNS #Results TABLE ([id] [bigint] IDENTITY(1,1) NOT NULL, Items nvarchar(4000))
AS
BEGIN
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
-- HAVE TO SET TO 1 SO IT DOESNT EQUAL Z
-- ERO FIRST TIME IN LOOP
SELECT #INDEX = 1
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results(Items) VALUES(#SLICE)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END
execute this function once in your database and now onward to access specific value you can write your query like below
DECLARE #VALUE VARCHAR(100);
SELECT TOP 1 #VALUE = Items FROM [dbo].[Array] ('some,thing,like,that' , ',') where id = 2
PRINT #VALUE
All you need to change is id in select statement. It'll accept only String values for now. But you can convert String to Int in SQL using CAST
I just created this function in hurry if you have any suggestions/modifications let me know...
I'm having a problem with random values being generated for each row in a result set in SQL Server 2008. I found a similar question here, but upon implementing the proposed answer, I saw the same problem as before. When running the query I have provided below, it seems that the same values will sometimes show up in consecutive rows, even though I'm calling for a new NEWID() with each row.
DECLARE #Id int = 0
DECLARE #Counter int = 1
DECLARE #Value int
CREATE TABLE #Table1
(
id int identity(1,1)
,Value int
)
WHILE #Counter < 100000
BEGIN
INSERT INTO #Table1 (Value)
SELECT CAST(RAND(CHECKSUM(NEWID())) * 100000 as INT)
SET #Counter += 1
END
SET #Counter = 0
WHILE #Counter < 5
BEGIN
SELECT
#Value = T.Value
,#Id = T.id
FROM #Table1 T
WHERE T.id = CAST(RAND(CHECKSUM(NEWID())) * 100000 as INT) + 1 + #Counter
IF #Id <> 0
SELECT #Value AS Value ,#Id as ID
SET #Counter += 1
END
DROP TABLE #Table1
If I change the INT to a BIGINT, as suggested in the link I provided, nothing is solved, so I don't believe that it's an "overflow" issue.
If I take the calculation out of the select, I don't get the doubled rows:
DECLARE #Id int = 0
DECLARE #Counter int = 1
DECLARE #Value int
-- new variable
DECLARE #DERIVED INT
CREATE TABLE #Table1
(
id int identity(1,1)
,Value int
)
WHILE #Counter < 100000
BEGIN
INSERT INTO #Table1 (Value)
SELECT CAST(RAND(CHECKSUM(NEWID())) * 100000 as INT)
SET #Counter += 1
END
SET #Counter = 0
WHILE #Counter < 5
BEGIN
--set here to remove calculation from the select
SET #DERIVED = CAST(RAND(CHECKSUM(NEWID())) * 100000 as INT) + 1 + #Counter;
SELECT
#Value = T.Value
,#Id = T.id
FROM #Table1 T
WHERE T.id = #DERIVED
IF #Id <> 0
SELECT #Value AS Value ,#Id as ID;
SET #Counter += 1
END
DROP TABLE #Table1
I'm seeing the duplicates every time with the pseudorandom generator inside the select. Oddly enough, I get about the same frequency of duplicates on the insert loop whether or not the calculation is inside the insert... select. It could be coincidence, since we are dealing with a randomly selected number. Note also, that since you're adding to the pseudorandom result, the results aren't technically duplicates. They're descending sequences:
11111 + 1 + 1 = 11113
11110 + 1 + 2 = 11113
Same overall result, different pseudorandom result. However, if I change
CAST(RAND(CHECKSUM(NEWID())) * 100000 as INT) + 1 + #Counter
to
CAST(RAND(CHECKSUM(NEWID())) * 100000 as INT) + #Counter + #Counter
I still consistently get duplicates. That implies that the optimizer may be caching/re-using values, at least on the select. I'd call that improper for a non-deterministic function call. I get similar results on 10.0.1600 and 10.50.1600 (2008 RTM and 2008R2 RTM).
I have a table which contains header information for transactions. The transactions belong to different projects.
In the header I have columns:
rhguid - uniqueidentifier
rhserial - int
rh_projectID - int
First I insert the row (there's more columns)
Then I calculate the serial number for that project:
update responseheader
set rhSerial = 1 + (select isnull(max(rhSerial), 0)
from responseheader
where (rhstatus = 0) AND (rh_projectID = 1234))
where
(rhGUID = <preassignedGUID>);
However when there are many transactions happening at the same time for a project I am finding duplicate rhserial values.
I'm doing this in classic ASP with SQL Server 2008.
Is there a better way?
From your example, it doesn't look like you're using a transaction. My guess is that the SELECT portion of the statement is running as READ UNCOMMITTED, otherwise you would not see duplicates. There are ways to start transactions with ADO, but I prefer using stored procedures instead.
Try implementing something like this:
CREATE PROC dbo.ResponseHeader_Insert
<more data to insert>,
#ProjectID INT,
#Status SMALLINT
as
insert responseheader (column names here)
select <param values here>, isnull(max(rhSerial), 0) + 1
from responseheader
where (rhstatus = #Status) AND (rh_projectID = #ProjectID))
If this doesn't work for ya, try creating sequence tables (one for each sequence).
create table <tablename> (
SeqID int identity(1,1) primary key,
SeqVal varchar(1)
)
Create a procedure to get the next identity:
create procedure GetNewSeqVal_<tablename>
as
begin
declare #NewSeqValue int
set NOCOUNT ON
insert into <tablename> (SeqVal) values ('a')
set #NewSeqValue = scope_identity()
delete from <tablename> WITH (READPAST)
return #NewSeqValue
end
If there are too many sequence tables that need to be created or you want to create sequences on the fly, try this approach:
Create table AllSequences (
SeqName nvarchar(255) primary key, -- name of the sequence
Seed int not null default(1), -- seed value
Incr int not null default(1), -- incremental
Currval int
)
Go
create procedure usp_CreateNewSeq
#SeqName nvarchar(255),
#seed int = 0,
#incr int = 1
as
begin
declare #currval int
if exists (
select 1 from AllSequences
where SeqName = #SeqName )
begin
print 'Sequence already exists.'
return 1
end
if #seed is null set #seed = 1
if #incr is null set #incr = 1
set #currval = #seed
insert into AllSequences (SeqName, Seed, Incr, CurrVal)
values (#SeqName, #Seed, #Incr, #CurrVal)
end
go
create procedure usp_GetNewSeqVal
#SeqName nvarchar(255)
as
begin
declare #NewSeqVal int
set NOCOUNT ON
update AllSequences
set #NewSeqVal = CurrVal = CurrVal+Incr
where SeqName = #SeqName
if ##rowcount = 0 begin
print 'Sequence does not exist'
return
end
return #NewSeqVal
end
go