I need some help with a simple (simple in PostgreSQL, but I need in SQL Server 2008) update from select statement. I don't know how to pass "values" from rows as variables to the select statement in from clause. This is what i've done.
DECLARE #OldAnswerValue INT = 7;
DECLARE #Type INT =3;
SELECT A.Id as NewAnswer
FROM tblEvaluationAnswers A
WHERE A.AnswerValue=
CASE #OldAnswerValue
WHEN 0 THEN 1
WHEN 1 THEN 2
...
WHEN 9 THEN 5
END
AND AnswerType=#Type
and my update will look like
UPDATE transPersonEvaluation
SET UserAnswer=PEA.NewAnswer
FROM ( ) as PEA --here the select statement inside from
but I don't know how to pass #OldAnswerValue and #Type as parameters into the from clause. This values are extracted from each row of transPersonEvaluation wich I am updating.
In PostgreSQL I think it is like
UPDATE transPersonEvaluation PE
SET UserAnswer=PEA.NewAnswer
FROM (
SELECT A.Id as NewAnswer
FROM tblEvaluationAnswers A ... where A.AnswerType=PE.AnswerType) as PEA;
but it is throwing syntax error on sql server 2008.
Any help would be appreciated, Thanks!
in sql server your query would look like this.
UPDATE PE
SET PE.UserAnswer=PEA.NewAnswer
FROM transPersonEvaluation PE
JOIN
(
SELECT A.Id as NewAnswer
FROM tblEvaluationAnswers A ... ) as PEA ON PEA.AnswerType = PE.AnswerType;
Related
I am creating a SQL Server stored procedure. It's a simple SELECT query that I am building. One of the parameters is to look for a flag parameter. If that parameter is left blank, then the SELECT should default to NOT having the WHERE clause at all.
CREATE PROCEDURE sprocA
#flagInd int
AS
BEGIN
SELECT intID, strQuestion, strAnswer, intCategory, intOrder
FROM tblA
-- Right here is where I am looking for the logic of the #flagInd to be evaluated.....
-- if #flagInd = 1 then 'WHERE flgInd=1'
-- else if #flagInd=0 then 'WHERE flgInd=0'
-- else if #flagInd IS NULL then ''
It's just a simple query and a simple thought I had, not sure if it can be done without nesting and rewriting the whole SELECT statement as part of of the IF statement.
This can be done like:
SELECT intID, strQuestion, strAnswer, intCategory, intOrder
FROM tblA
WHERE flgInd = #flgInd OR #flgInd IS NULL;
You can also use a CASE expression:
SELECT intID, strQuestion, strAnswer, intCategory, intOrder
FROM tblA
WHERE CASE
WHEN flgInd = #flgInd THEN 1
WHEN #flgInd IS NULL THEN 1
ELSE 0
END = 1;
There appears to just be a one to one mapping (from the parameter to the column) so why not use a simple where clause?
CREATE PROCEDURE sprocA
#flagInd int
AS
BEGIN
SELECT intID, strQuestion, strAnswer, intCategory, intOrder
FROM tblA WHERE flgInd = #flagInd;
I have a query like this:
DECLARE #year_start INT
DECLARE #year_end INT
SET #year_start = 2005
SET #year_end = 2014
; WITH p_year AS
(
SELECT p_year = #year_start
UNION ALL
SELECT p_year = p_year + 1
FROM p_year
WHERE p_year < #year_end
),
Interval AS
(---
),
CTE AS
(---
),
CTE_1 AS
(---
)
SELECT something
FROM CTE_1
WHERE Rank <= 3
ORDER BY something
I tried it using creating table valued function but can't get that how to manipulate with variables in the table valued function declaration.
Whereas I tried creating table valued function as:
CREATE FUNCTION P_Count()
RETURNS TABLE
AS
DECLARE ...
...
I want to make it a view but Declare statement not allows me. How can I make it a view?
your create function script misses a BEGIN:
CREATE FUNCTION P_Count()
RETURNS #tableName TABLE (structure here)
AS
BEGIN
DECLARE...
...
RETURN;
END;
here is the syntax reference on msdn
Maliks, I suppose, some were confused with your SQL. It was not immediately apparent that you use a recursive CTE to generate years in a range. There are lots of awesome ways to generate a sequence of integers (or numbers, in general) that can be combined with a CTE to emulate variables in a view. If numbers are generated way too often, consider building a separate (and indexed) table for them.
Here is what I think you were looking for. I omit the CTEs, rank and grouping you have not defined in your question. You can modify it as you wish:
WITH params AS (SELECT BegYr = 2005, EndYr=2014),
nums AS (SELECT DISTINCT n = number FROM master..spt_values WHERE number>=0)
SELECT Yr=BegYr + n FROM nums, params
WHERE n <= EndYr - BegYr
More generally, here is a sample view query that uses CTE to nicely emulate internal variable construction. You can test-run it in your version of SQL Server.
CREATE VIEW vwImportant_Users AS
WITH params AS (
SELECT
varType='%Admin%',
varMinStatus=1)
SELECT status, name
FROM sys.sysusers, params
WHERE status > varMinStatus OR name LIKE varType
SELECT * FROM vwImportant_Users
yielding output:
status name
12 dbo
0 db_accessadmin
0 db_securityadmin
0 db_ddladmin
also via JOIN
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers INNER JOIN params ON 1=1
WHERE status > varMinStatus OR name LIKE varType
also via CROSS APPLY
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers CROSS APPLY params
WHERE status > varMinStatus OR name LIKE varType
I'm trying to move from SQL Server to an Oracle database. I have to move my stored procedure from SQL Server to Oracle that do a query from multiple table with an INNER JOIN. I am trying to clarify few things here.
SQL Server stored procedure:
[dbo].[QueryAll]
#score1_min int = 0,
#score1_max int = 999,
#type1 varchar (1) = '%',
AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM FUNIJ1 uni
INNER JOIN CAPI99 api99 on api99.application_id = uni.application_id
INNER JOIN CAPI41 api41 on api41.application_id = uni.application_id
INNER JOIN CAPI10 api10 on api10.application_id = uni.application_id
WHERE
api10.score1 BETWEEN #score1_min AND #score1_max
AND uni.type1 LIKE #type1
END
And my Oracle procedure
create or replace PROCEDURE QUERYALL
(
SCORE1_MIN IN NUMBER DEFAULT 0
, SCORE1_MAX IN NUMBER DEFAULT 999
, TYPE IN VARCHAR2
)
AS
BEGIN
SELECT *
FROM FUNIJ1 uni
INNER JOIN CAPI99 on CAPI99.APPLICATION_ID = uni.APPLICATION_ID
INNER JOIN CAPI41 on CAPI41.APPLICATION_ID = uni.APPLICATION_ID
INNER JOIN CAPI10 on CAPI10.APPLICATION_ID = uni.APPLICATION_ID
WHERE
CAPI10.score1 BETWEEN score1_min AND score1_max
AND uni.type LIKE type
END REPOQUERYALL ;
I used % as default query parameter to return all values in SQL Server
in case of no input from user. I am not sure what I have to use in Oracle as default value to return all.
List item Oracle is using new term INTO following to SELECT *. I am not sure whether I need to use INTO or cursor in this case. I don't know WHICH will be appropriate here and HOW to use it.
I'd appreciate if anybody can transfer this SQL Server to an Oracle procedure. I am not sure that my Oracle is 100% correct.
Here is what you need to understand about Oracle stored procedure - unlike in SQL Server, you can't just do SELECT ... in any programming block, unless this is subselect or select... into....
If the goal is to return record set from procedure, in Oracle, you have to add a Sys_RefCursor output parameter and open this ref cursor with your select statement.
You're not far away - check this example .And remember, when you do Open <cursor_name> FOR ..., what comes after FOR can be dynamic SQL string or just compiled SQL.
Here is the code that worked for me with Sys_Cursor. Thanks #TS for the help that guide me to this answer.
create or replace PROCEDURE QUERYALL
(
o_Cursor OUT SYS_REFCURSOR
)
AS
BEGIN
O_Cursor := NULL;
OPEN O_Cursor FOR
SELECT * FROM FUNIJ1
INNER JOIN CAPI99 on CAPI99.APPLICATION_ID = FUNIJ1 .APPLICATION_ID
INNER JOIN CAPI41 on CAPI41.APPLICATION_ID = FUNIJ1 .APPLICATION_ID
INNER JOIN CAPI10 on CAPI10.APPLICATION_ID = FUNIJ1 .APPLICATION_ID
WHERE
----
----
END QUERYALL;
When you use this procedure in Java to display the table, you need to call Sys_Cursor into Resultset.
String sp= "{CALL QUERYALL(?)}"; // Procedure calling with Sys_Cursor
cst = con.prepareCall(sql);
cst.registerOutParameter(1, OracleTypes.CURSOR);
cst.executeUpdate();
rs = (ResultSet) cst.getObject(1);
while(rs.next()) {
----
----
}
I know we can use LIKE for pattern matching, however, here is what want to do.
I have a table, which has a column, 'Pattern', the values are like:
host1%
%host2
....
I have another table, which has a column, 'Host'. The question is: how can I check whether the values in 'Host' table do not match any patterns in 'Pattern'?
If it is too complex, then a simplified question is: How can I check whether the values in 'Host' do not StartWith any strings in 'Pattern'?
We can use loop, but is there a better way? ideally, it should work for ql server 2008, but latest version will do.
thanks
Use where not exists followed by a subquery which checks each pattern against the current row of the table containing your data. i.e.
where not exists
(
select top 1 1
from #patterns p
where d.datum like p.pattern
)
Full Code for Working Example: SQL Fiddle
declare #patterns table
(
pattern nvarchar(16) not null
)
declare #data table
(
datum nvarchar(16) not null
)
insert #patterns
values ('host1%')
,('%host2')
insert #data
values ('host1234')
, ('234host1')
, ('host2345')
, ('345host2')
select *
from #data d
where not exists
(
select top 1 1
from #patterns p
where d.datum like p.pattern
)
select t1.host
from table_1 t1
left join table_2 t2 on t1.host like t2.pattern
where t2.pattern is null
MyTableA has several million records. On regular occasions every row in MyTableA needs to be updated with values from TheirTableA.
Unfortunately I have no control over TheirTableA and there is no field to indicate if anything in TheirTableA has changed so I either just update everything or I update based on comparing every field which could be different (not really feasible as this is a long and wide table).
Unfortunately the transaction log is ballooning doing a straight update so I wanted to chunk it by using UPDATE TOP, however, as I understand it I need some field to determine if the records in MyTableA have been updated yet or not otherwise I'll end up in an infinite loop:
declare #again as bit;
set #again = 1;
while #again = 1
begin
update top (10000) MyTableA
set my.A1 = their.A1, my.A2 = their.A2, my.A3 = their.A3
from MyTableA my
join TheirTableA their on my.Id = their.Id
if ##ROWCOUNT > 0
set #again = 1
else
set #again = 0
end
is the only way this will work if I add in a
where my.A1 <> their.A1 and my.A2 <> their.A2 and my.A3 <> their.A3
this seems like it will be horribly inefficient with many columns to compare
I'm sure I'm missing an obvious alternative?
Assuming both tables are the same structure, you can get a resultset of rows that are different using
SELECT * into #different_rows from MyTable EXCEPT select * from TheirTable and then update from that using whatever key fields are available.
Well, the first, and simplest solution, would obviously be if you could change the schema to include a timestamp for last update - and then only update the rows with a timestamp newer than your last change.
But if that is not possible, another way to go could be to use the HashBytes function, perhaps by concatenating the fields into an xml that you then compare. The caveat here is an 8kb limit (https://connect.microsoft.com/SQLServer/feedback/details/273429/hashbytes-function-should-support-large-data-types) EDIT: Once again, I have stolen code, this time from:
http://sqlblogcasts.com/blogs/tonyrogerson/archive/2009/10/21/detecting-changed-rows-in-a-trigger-using-hashbytes-and-without-eventdata-and-or-s.aspx
His example is:
select batch_id
from (
select distinct batch_id, hash_combined = hashbytes( 'sha1', combined )
from ( select batch_id,
combined =( select batch_id, batch_name, some_parm, some_parm2
from deleted c -- need old values
where c.batch_id = d.batch_id
for xml path( '' ) )
from deleted d
union all
select batch_id,
combined =( select batch_id, batch_name, some_parm, some_parm2
from some_base_table c -- need current values (could use inserted here)
where c.batch_id = d.batch_id
for xml path( '' ) )
from deleted d
) as r
) as c
group by batch_id
having count(*) > 1
A last resort (and my original suggestion) is to try Binary_Checksum? As noted in the comment, this does open the risk for a rather high collision rate.
http://msdn.microsoft.com/en-us/library/ms173784.aspx
I have stolen the following example from lessthandot.com - link to the full SQL (and other cool functions) is below.
--Data Mismatch
SELECT 'Data Mismatch', t1.au_id
FROM( SELECT BINARY_CHECKSUM(*) AS CheckSum1 ,au_id FROM pubs..authors) t1
JOIN(SELECT BINARY_CHECKSUM(*) AS CheckSum2,au_id FROM tempdb..authors2) t2 ON t1.au_id =t2.au_id
WHERE CheckSum1 <> CheckSum2
Example taken from http://wiki.lessthandot.com/index.php/Ten_SQL_Server_Functions_That_You_Have_Ignored_Until_Now
I don't know if this is better than adding where my.A1 <> their.A1 and my.A2 <> their.A2 and my.A3 <> their.A3, but I would definitely give it a try (assuming SQL Server 2005+):
declare #again as bit;
set #again = 1;
declare #idlist table (Id int);
while #again = 1
begin
update top (10000) MyTableA
set my.A1 = their.A1, my.A2 = their.A2, my.A3 = their.A3
output inserted.Id into #idlist (Id)
from MyTableA my
join TheirTableA their on my.Id = their.Id
left join #idlist i on my.Id = i.Id
where i.Id is null
/* alternatively (instead of left join + where):
where not exists (select * from #idlist where Id = my.Id) */
if ##ROWCOUNT > 0
set #again = 1
else
set #again = 0
end
That is, declare a table variable for collecting the IDs of the rows being updated and use that table for looking up (and omitting) IDs that have already been updated.
A slight variation on the method would be to use a local temporary table instead of a table variable. That way you would be able to create an index on the ID lookup table, which might result in better performance.
If schema change is not possible. How about using trigger to save off the Ids that have changed. And only import/export those rows.
Or use trigger to export it immediately.