NULL values in multivalue parameter - sql-server

This stored procedure beneath fills up my Projectphase parameter. So as you can see, the user first has to select #PurchaseOrder, which will then fill up the Projectphase Parameter.
CREATE PROCEDURE [dbo].[USP_GetProjectPhase]
#PurchaseOrder INT
AS
SELECT
pp.ProjectPhaseID, pp.Phase
FROM
ProjectPhase pp
WHERE
#PurchaseOrder = pp.PurchaseOrderId
Now when the user selects a PurchaseOrder that indeed has Projectphases, everything goes well. The issue situates itself in the purchaseorders that don't have a ProjectPhase.
The query that is used for my dataset shown on the report has the following line in the WHERE clause. It's a multivalue parameter cause the user needs to be able to select multiple Projectphases.
WHERE
reg.ProjectPhaseId IN (SELECT Value
FROM fnLocal_CmnParseList(#Phase,','))
I've tried UNIONS with NULL, NULL. I've tried stuff with ISNULL but I can't seem to be getting the query to execute when #ProjectPhase is NULL.
Some help would be greatly appreciated cause I've been cracking my head on this for too long now. Thanks

Finally found the answer:
[dbo].[USP_GetProjectPhase] #PurchaseOrder INT
AS
SELECT -1 AS 'ProjectPhaseID'
,'No Filter' AS 'Phase'
UNION
SELECT pp.ProjectPhaseID
,pp.Phase
FROM ProjectPhase pp
WHERE #PurchaseOrder = pp.PurchaseOrderId
In my query I changed the WHERE clause to:
WHERE (reg.ProjectPhaseId IN (SELECT Value FROM fnLocal_CmnParseList(#Phase,',')) OR #Phase = '-1')

Related

SQL - How can I return a value from a different table base on a parameter?

SQL - How can I return a value from a different table base on a parameter
First time poster, long time reader:
I am using a custom Excel function that allows be to pass parameters and build a SQL string that returns a value. This is working fine. However, I would like to choose among various tables based on the parameters that are passed.
At the moment I have two working functions with SQL statements look like this:
_______FUNCTION ONE________
<SQLText>
SELECT PRODDTA.TABLE1.T1DESC as DESCRIPTION
FROM PRODDTA.TABLE1
WHERE PRODDTA.TABLE1.T1KEY = '&PARM02'</SQLText>
_______FUNCTION TWO________
<SQLText>
SELECT PRODDTA.TABLE2.T2DESC as DESCRIPTION
FROM PRODDTA.TABLE2
WHERE PRODDTA.TABLE2.T2KEY = '&PARM02'</SQLText>
So I am using IF logic in Excel to check the first parameter and decide which function to use.
It would be much better if I could do a single SQL statement that could pick the right table based on the 1st parameter. Logically something like this:
_______FUNCTIONS COMBINED________
IF '&PARM02' = “A” THEN
SELECT PRODDTA.TABLE1.T1DESC as DESCRIPTION
FROM PRODDTA.TABLE1
WHERE PRODDTA.TABLE1.T1KEY = '&PARM02'
ELSE IF '&PARM02' = “B” THEN
SELECT PRODDTA.TABLE2.T2DESC as DESCRIPTION
FROM PRODDTA.TABLE2
WHERE PRODDTA.TABLE2.T2KEY = '&PARM02'
ELSE
DESCRIPTION = “”
Based on another post Querying different table based on a parameter I tried this exact syntax with no success
<SQLText>
IF'&PARM02'= "A"
BEGIN
SELECT PRODDTA.F0101.ABALPH as DESCRIPTION
FROM PRODDTA.F0101
WHERE PRODDTA.F0101.ABAN8 = '&PARM02'
END ELSE
BEGIN
SELECT PRODDTA.F4801.WADL01 as DESCRIPTION
FROM PRODDTA.F4801
WHERE PRODDTA.F4801.WADOCO = '&PARM02'
END</SQLText>
You could try using a JOIN statement.
http://www.sqlfiddle.com/#!9/23461d/1
Here is a fiddle showing two tables.
The following code snip will give you the values from both tables, using the Key as the matching logic.
SELECT Table1.description, Table1.key, Table2.description
from Table1
Join Table2 on Table1.key = Table2.key
Here's one way to do it. If PARM03='Use Table1' then the top half of the union will return records and vice versa. This won't necessarily product good performance though. You should consider why you are storing data in this way. It looks like you are partitioning data across different tables which is a bad idea.
SELECT PRODDTA.TABLE1.T1DESC as DESCRIPTION
FROM PRODDTA.TABLE1
WHERE PRODDTA.TABLE1.T1KEY = '&PARM02'
AND &PARM03='Use Table1'
UNION ALL
SELECT PRODDTA.TABLE2.T2DESC as DESCRIPTION
FROM PRODDTA.TABLE2
WHERE PRODDTA.TABLE2.T2KEY = '&PARM02'</SQLText>
AND &PARM03='Use Table2'

Report builder - using different queries according to parameter

I am trying to make a report, where I can select a multiple values from a parameter - and then make a query, where i state "where in (#partner)"
However, my problems occours, when I want to make a value, that will not do the "where in (#partner)", but will simply select all from the same query, without the where in clause - as not all rows in my db table, have the specific values set, so I want to catch them too.
All the values for the parameter is selected from a query, and I have a union on it, to create a value for the one, where I need to select all - not using the where in.
It actually works, if only one value from the parameter list is chosen - but as soon as I try to select 2 or more, I get the error "query execution failed for dataset1......"
The value of the parameter value, that is used for selecting all is 0, as you see in the code - and it does work as I can execute both select statements below, but not when I select more then 1 value from the parameter list.
IF #partner = 0
BEGIN
SELECT
thedata
FROM
thetable
WHERE
thedata = 3
END
ELSE
SELECT
thedata
FROM
thetable
WHERE
thedata = 3
and partner in (#partner)
END
ELSE
Hope there is some clever guys out there:) Thanks
Just do:
SELECT thedata
FROM thetable
WHERE thedata = 3
AND (partner IN (#partner) or #partner = 0)

How do I update an XML column in sql server by checking for the value of two nodes including one which needs to do a contains (like) comparison

I have an xml column called OrderXML in an Orders table...
there is an XML XPath like this in the table...
/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail
There InternalOrderDetails contains many InternalOrderDetail nodes like this...
<InternalOrderDetails>
<InternalOrderDetail>
<Item_Number>FBL11REFBK</Item_Number>
<CountOfNumber>10</CountOfNumber>
<PriceLevel>FREE</PriceLevel>
</InternalOrderDetail>
<InternalOrderDetail>
<Item_Number>FCL13COTRGUID</Item_Number>
<CountOfNumber>2</CountOfNumber>
<PriceLevel>NONFREE</PriceLevel>
</InternalOrderDetail>
</InternalOrderDetails>
My end goal is to modify the XML in the OrderXML column IF the Item_Number of the node contains COTRGUID (like '%COTRGUID') AND the PriceLevel=NONFREE. If that condition is met I want to change the PriceLevel column to equal FREE.
I am having trouble with both creating the xpath expression that finds the correct nodes (using OrderXML.value or OrderXML.exist functions) and updating the XML using the OrderXML.modify function).
I have tried the following for the where clause:
WHERE OrderXML.value('(/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/Item_Number/node())[1]','nvarchar(64)') like '%13COTRGUID'
That does work, but it seems to me that I need to ALSO include my second condition (PriceLevel=NONFREE) in the same where clause and I cannot figure out how to do it. Perhaps I can put in an AND for the second condition like this...
AND OrderXML.value('(/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/PriceLevel/node())[1]','nvarchar(64)') = 'NONFREE'
but I am afraid it will end up operating like an OR since it is an XML query.
Once I get the WHERE clause right I will update the column using a SET like this:
UPDATE Orders SET orderXml.modify('replace value of (/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/PriceLevel[1]/text())[1] with "NONFREE"')
However, I ran this statement on some test data and none of the XML columns where updated (even though it said zz rows effected).
I have been at this for several hours to no avail. Help is appreciated. Thanks.
if you don't have more than one node with your condition in each row of Orders table, you can use this:
update orders set
data.modify('
replace value of
(
/Order/InternalInformation/InternalOrderBreakout/
InternalOrderHeader/InternalOrderDetails/
InternalOrderDetail[
Item_Number[contains(., "COTRGUID")] and
PriceLevel="NONFREE"
]/PriceLevel/text()
)[1]
with "FREE"
');
sql fiddle demo
If you could have more than one node in one row, there're a several possible solutions, none of each is really elegant, sadly.
You can reconstruct all xmls in table - sql fiddle demo
or you can do your updates in the loop - sql fiddle demo
This may get you off the hump.
Replace #HolderTable with the name of your table.
SELECT T2.myAlias.query('./../PriceLevel[1]').value('.' , 'varchar(64)') as MyXmlFragmentValue
FROM #HolderTable
CROSS APPLY OrderXML.nodes('/InternalOrderDetails/InternalOrderDetail/Item_Number') as T2(myAlias)
SELECT T2.myAlias.query('.') as MyXmlFragment
FROM #HolderTable
CROSS APPLY OrderXML.nodes('/InternalOrderDetails/InternalOrderDetail/Item_Number') as T2(myAlias)
EDIT:
UPDATE
#HolderTable
SET
OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue"')
WHERE
OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel)[1]', 'varchar(64)') = 'FREE'
print ##ROWCOUNT
Your issue is the [1] in the above.
Why did I put it there?
Here is a sentence from the URL listed below.
Note that the target being updated must be, at most, one node that is explicitly specified in the path expression by adding a "[1]" at the end of the expression.
http://msdn.microsoft.com/en-us/library/ms190675.aspx
EDIT.
I think I've discovered the the root of your frustration. (No fix, just the problem).
Note below, the second query works.
So I think the [1] is some cases is saying "only ~~search~~ the first node".....and not (as you and I were hoping)...... "use the first node..after you find a match".
UPDATE
#HolderTable
SET
OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue001"')
WHERE
OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel[text() = "NONFREE"])[1]', 'varchar(64)') = 'NONFREE'
/* and OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/Item_Number)[1]', 'varchar(64)') like '%COTRGUID' */
UPDATE
#HolderTable
SET
OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue002"')
WHERE
OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel[text() = "FREE"])[1]', 'varchar(64)') = 'FREE'
Try this :
;with InternalOrderDetail as (SELECT id,
Tbl.Col.value('Item_Number[1]', 'varchar(40)') Item_Number,
Tbl.Col.value('CountOfNumber[1]', 'int') CountOfNumber,
case
when Tbl.Col.value('Item_Number[1]', 'varchar(40)') like '%COTRGUID'
and Tbl.Col.value('PriceLevel[1]', 'varchar(40)')='NONFREE'
then 'FREE'
else
Tbl.Col.value('PriceLevel[1]', 'varchar(40)')
end
PriceLevel
FROM (select id ,orderxml from demo)
as a cross apply orderxml.nodes('//InternalOrderDetail')
as
tbl(col) ) ,
cte_data as(SELECT
ID,
'<InternalOrderDetails>'+(SELECT ITEM_NUMBER,COUNTOFNUMBER,PRICELEVEL
FROM InternalOrderDetail
where ID=Results.ID
FOR XML AUTO, ELEMENTS)+'</InternalOrderDetails>' as XML_data
FROM InternalOrderDetail Results
GROUP BY ID)
update demo set orderxml=cast(xml_data as xml)
from demo
inner join cte_data on demo.id=cte_data.id
where cast(orderxml as varchar(2000))!=xml_data;
select * from demo;
SQL Fiddle
I have handled following cases :
1. As required both where clause in question.
2. It will update all <Item_Number> like '%COTRGUID' and <PriceLevel>= NONFREE in one
node, not just the first one.
It may require minor changes for your data and tables.

Filtering by ALL or by selected attribute

Excuse my language or SQL/Reporting wording
I am generating a report using Reporting Services where I have 2 drop down lists in order to show only by period and by category. I want it so if I select and I am shown all entries and if selected from any of the 2 drop downs then filter by those selections. I have a stored procedure which states the following on it's WHERE clause:
WHERE (dbo.PERIOD_LIST.PERIOD_DESC = #period) OR (dbo.CATEGORY.CATEGORY_DESC = #category)
However I cannot get this to work on Reporting Services/Visual Studio. I am shown ALL the entries instead of the filtered ones. I initialize #period and #category as NULL. So how can I make it so the report shows all rows when both attributes are null and still be able to filter by each or both of them?
How can I achieve this?
Edit: I used the suggestion Filip Popović gave me. If you're having this problem modify your prepared statement and make sure you refresh fields on your data sets since there's additional clauses on your prepared statement!
Note that in SQL, NULL = NULL is never evaluated to true. You can take it as NULL is not nothing it is something but unspecified. And You can't compare two unspecified values. You have to test COL1 IS NULL to get true if column has null value.
Try this:
WHERE ((dbo.PERIOD_LIST.PERIOD_DESC = #period) OR (#period IS NULL))
AND ((dbo.CATEGORY.CATEGORY_DESC = #category) OR (#category IS NULL))
Check the parameter for NULL as part of the condition:
WHERE ((#period IS NULL) OR (dbo.PERIOD_LIST.PERIOD_DESC = #period))
AND ((#category IS NULL) OR (dbo.CATEGORY.CATEGORY_DESC = #category))

Counting records in SQL Server

Take a look at this SP.
ALTER PROCEDURE [dbo].[sp_GetRecTitleVeh]
AS
BEGIN
select
a.StockNo, c.ClaimNo,
v.VIN, v.[Year],v.Make, v.Model,
c.DOAssign, t.DOLoss, t.RecTitleDate
From
dbo.Assignments a,
dbo.Assignment_ClaimInfo c,
dbo.Assignment_TitleInfo t,
dbo.Assignment_VehicleInfo v
Where
a.AssignmentID= c.AssignmentID and
c.AssignmentID= t.AssignmentID and
t.AssignmentID= v.AssignmentID and
t.RecTitleDate is not null and
c.InsuranceComp = 'XYZ' and
a.StockNo not in (select StockNo from dbo.Invoice where InvoiceType = 'Payment Invoice')
order by t.RecTitleDate
END
This SP works fine and gives me required result.
What i need is to ask that is there any shortest way to count records obtained by executing this SP. For ex. i am trying like this
select count(*) from sp_GetRecTitleVeh
I know that there is a solution like -
ALTER PROCEDURE [dbo].[sp_CountRecTitleVeh]
AS
BEGIN
select
count(a.StockNo)
From
dbo.Assignments a,
dbo.Assignment_ClaimInfo c,
dbo.Assignment_TitleInfo t,
dbo.Assignment_VehicleInfo v
Where
a.AssignmentID= c.AssignmentID and
c.AssignmentID= t.AssignmentID and
t.AssignmentID= v.AssignmentID and
t.RecTitleDate is not null and
c.InsuranceComp = 'XYZ' and
a.StockNo not in (select StockNo from dbo.Invoice where InvoiceType = 'Payment Invoice')
order by t.RecTitleDate
END
Do you have any idea how could i count records got by executing SP.
Thanks for sharing your valuable time.
Try...
EXEC sp_GetRecTitleVeh
SELECT ##Rowcount
immediately after your select do select ##rowcount. this will give you the number of affected rows.
also start using the proper join syntax. the old syntax for left (=) and right jons (=) is deprecated.
I believe that ##rowcount is the preferred approach.
But, just for the record, if you handle the SqlCommand.StatementCompleted event, you can get the DONE_IN_PROC message which is returned to the client. That includes the number of rows affected. But you can't use SET NOCOUNT ON if you want to get DONE_IN_PROC, so performance will be hindered a bit if you do this.

Resources