I have a stored proc that has several parameters. Most of them allow for multiple selections in a drop-down menu. They are: vOwner, vFunction, vSite, vStatus (all multiple selections allowed and the "Select All" is also enabled), and then vStartDate and vEndDate.
For some reason, when I choose "Select All" for every parameter, SSRS cuts off some of the records. It seems to report everything except records for the very last "owner." I'm looking for a clue as to why this might be happening. It happens when I select just one date's worth of data. It's as though that last owner isn't even being picked up as part of the data set.
Where SSRS is concerned, the settings are fairly simple. I have a data set that references the stored procedure (below), and one for each of the lookup tables i have (function, status, etc.) Any help is appreciated. Let me know if other information is needed. Thanks!
Stored Procedure:
#vOwner varchar(1000) = NULL,
#vFunction varchar(1000) = NULL,
#vStatus varchar(1000) = NULL,
#vLocation varchar(1000) = NULL,
#vBeginDate datetime = NULL,
#vEndDate datetime = NULL
AS
BEGIN
--Allow for multiple owners, functions, etc. to be selected in SSRS.
Select #vOwner = ', ' + #vOwner + ', '
create table #Owner
(
Owner varchar(1000)
)
Insert Into #Owner
Select ManagerLastName + ', ' + ManagerFirstName As Owner
From Managers
Where #vOwner Like '%, ' + ManagerLastName + ', ' + ManagerFirstName + ', %'
Group By ManagerLastName, ManagerFirstName
--Function
Select #vFunction = ', ' + #vFunction + ', '
create table #Function
(
Functions varchar(1000)
)
Insert Into #Function
Select Functions
From Functions
Where #vFunction Like '%, ' + Functions + ', %'
Group By Functions
--Status
Select #vStatus = ', ' + #vStatus + ', '
create table #Status
(
IssueStatus varchar(1000)
)
Insert Into #Status
Select IssueStatus
From IssueStatus
Where #vStatus Like '%, ' + IssueStatus + ', %'
Group By IssueStatus
--Sites
Select #vLocation = ', ' + #vLocation + ', '
create table #Sites
(
siteName varchar(1000)
)
Insert Into #Sites
Select siteName
From Sites
Where #vLocation Like '%, ' + siteName + ', %'
Group By siteName
Select
recID,
siteName
functions
From issueInput
Where
#vFunction Like '%, ' + functions + ', %'
And #vOwner Like '%, ' + ManagerLastName + ', ' + ManagerFirstName + ', %'
And #vStatus Like '%, ' + IssueStatus + ', %'
And #vLocation Like '%, ' + SiteName + ', %'
And (#vBeginDate Is Null Or #vBeginDate = 0 Or #vBeginDate <= Cast(Convert(varchar,(OpenDate),101) As datetime))
And (#vEndDate Is Null Or #vEndDate = 0 Or #vEndDate >= Cast(Convert(varchar,(OpenDate),101) As datetime))
Order by OpenDate
END
Is there a reason you using a stored procedure? It's possible to do what you want, but passing multiple values on a single parameter isn't natively supported by SQL Server. If you want to do this, you have to do some hack, which from the looks of your SQL, you have impelmented a work around.
If you embed the query in the rdl file, you can simply have an IN clause (i.e. IN(#vOwner)) and SSRS will insert the values into the query in a proper way such that it has the expected behavior. This way you are relying on something that was designed to work instead of having to work around a known limitation.
Looks like it wasn't a flaw in SSRS at all. After testing it out more in SSMS, I discovered that it was only the owner value that was being cut off at the end. I increased the #vOwner parameter from varchar(1000) to varchar(2000) and it is working fine now. I was simply passing too many characters into that parameter and it was getting truncated. Problem solved. Thanks to billinkc for that light bulb!
Related
I have this query that I'm passing 2 parameters, COUNTRY_REGION parameter and COST_CENTER parameter
I have the possibility to pass both parameters at the same time COST_CENTER and COUNTRY_REGION..... Or pass one or the other... This part is OK.
You can see in the first image below
SELECT
dwg.GEOGRAPHY_ID as geographyId
,INITCAP (lower (dwc.COUNTRY_REGION)) as countryRegion
,INITCAP (lower (dwc.COUNTRY_NAME)) as countryName
,dp.PROJECT_ID as projectId
FROM
DATALAKE.DWL_GEOGRAPHIES dwg
,DATALAKE.DWB_PROJECT dp
,DATALAKE.DWL_GEOGRAPHY_COUNTRIES dwgc
,DATALAKE.DWL_COUNTRY dwc
,DATALAKE.DWB_PROJECT_FINANCIAL dpf
,DATALAKE.DWL_GOLIVE dgl
where dwg.geography_id = dp.project_geography_id
and dwg.geography_id = dwgc.geography_id
and dwc.country_id = dwgc.country_id
and dp.PROJECT_ID = dpf.PROJECT_ID
and dpf.PROJECT_ID = dgl.PROJECT_ID
and dpf.FLAG_ACTIVE = 1
and ((dp.cost_center = (:costCenter) and INITCAP (lower (dwc.COUNTRY_REGION)) = (:countryRegion))
or (:costCenter IS null and INITCAP (lower (dwc.COUNTRY_REGION)) = (:countryRegion))
or (dp.cost_center = (:costCenter) and :countryRegion IS null)
)
order by dwc.COUNTRY_REGION
But I WANT TO HAVE THE OPTION TO PASSA TWO OR MORE IN THE SAME PARAMETER as in the image below...
example:
COUNTRY_REGION: Peru, Chile, Argentina
or
COST_CENTER : 10500, 1000, ... , ....
I would like help, I've tried several things and I can't proceed, thank you very much.
You cannot pass multiple values with a single bind variable.
What you can do is pass in a single string that contains a delimited list and match a sub-string of the list to the value:
SELECT *
FROM table_name
WHERE ', ' || :country_region_list || ', ' LIKE '%, ' || country_region || ', %'
OR ', ' || :cost_centre_list || ', ' LIKE '%, ' || cost_centre || ', %'
Which would make your query:
SELECT dwg.GEOGRAPHY_ID as geographyId
, INITCAP(dwc.COUNTRY_REGION) as countryRegion
, INITCAP(dwc.COUNTRY_NAME) as countryName
, dp.PROJECT_ID as projectId
FROM DATALAKE.DWL_GEOGRAPHIES dwg
INNER JOIN DATALAKE.DWB_PROJECT dp
ON (dwg.geography_id = dp.project_geography_id)
INNER JOIN DATALAKE.DWL_GEOGRAPHY_COUNTRIES dwgc
ON (dwg.geography_id = dwgc.geography_id)
INNER JOIN DATALAKE.DWL_COUNTRY dwc
ON (dwc.country_id = dwgc.country_id)
INNER JOIN DATALAKE.DWB_PROJECT_FINANCIAL dpf
ON (dp.PROJECT_ID = dpf.PROJECT_ID)
INNER JOIN DATALAKE.DWL_GOLIVE dgl
ON (dpf.PROJECT_ID = dgl.PROJECT_ID)
WHERE dpf.FLAG_ACTIVE = 1
AND (
', ' || :costCenter || ', ' LIKE '%, ' || dp.cost_center || ', %'
OR :costCenter IS null
)
AND (
', ' || :countryRegion || ', '
LIKE '%, ' || INITCAP(dwc.COUNTRY_REGION) || ', %'
OR :countryRegion IS null
)
AND (:costCenter IS NOT NULL OR :countryRegion IS NOT NULL)
order by dwc.COUNTRY_REGION
Hi I am trying to execute but getting error single row subquery returns more than one row.
update upld_mktprice
set (upld_mktprice.orig_security, upld_mktprice.stk_exch, upld_mktprice.stk_group, upld_mktprice.instr_type) =
(select security.security,nvl(upld_mktprice.stk_exch,
nvl(security.stk_exch,'DIRECT')),
security.stk_group,
decode(upld_mktprice.source,'FOREX','X','S') as instr_type -- HLAMUAT-1457146: Passing DIRECT as a default value for HLAM. confirmed by Dheeren/Prasanth.
from v_security_all security
where upld_mktprice.security = Decode(security.asset_type,'OPT',security.stk_sec_id||' '||substr(security.security,instrb(security.security, ' ', 1,1)+3, length(security.security)),security.stk_sec_id)
and rectype = 'L'),
upld_mktprice.currency = nvl(upld_mktprice.currency,''),
upld_mktprice.value_date = nvl(upld_mktprice.value_date,''),
upld_mktprice.amc_code = 'AMC'
Where exists (select 1
from v_security_all security
where upld_mktprice.security = Decode(security.asset_type,'OPT',security.stk_sec_id||' '||substr(security.security,instrb(security.security, ' ', 1,1)+3, length(security.security)),security.stk_sec_id)
and rectype = 'L')
and upld_mktprice.orig_security is null
and upld_mktprice.user_id = 'SRINIVAS'
and upld_mktprice.source = 'MKTPRICEMAN';
I think the error pretty much speaks for itself. The portion of your query below is returning more than one row. There is no way for us to validate because we do not have the data that you have. It might also be a bit easier to troubleshoot if you used table aliases in your update statement.
(SELECT security.security,
NVL (upld_mktprice.stk_exch, NVL (security.stk_exch, 'DIRECT')),
security.stk_group,
DECODE (upld_mktprice.source, 'FOREX', 'X', 'S') AS instr_type -- HLAMUAT-1457146: Passing DIRECT as a default value for HLAM. confirmed by Dheeren/Prasanth.
FROM v_security_all security
WHERE upld_mktprice.security =
DECODE (security.asset_type,
'OPT', security.stk_sec_id
|| ' '
|| SUBSTR (security.security,
INSTRB (security.security,
' ',
1,
1)
+ 3,
LENGTH (security.security)),
security.stk_sec_id)
AND rectype = 'L')
I am loading a file into a staging record using Application Engine. when ever there is blank in BU,Deptid etc... I have to capture what all columns are blank and update error text field with those values.
UPDATE SYSADM.PS_VI_EMP_TS SET ERR_TEXT =
SELECT ERROR FROM (SELECT * FROM (
SELECT CASE WHEN BUSINESS_UNIT = ' ' THEN 'BUSINESS_UNIT IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '7852429'
UNION
SELECT CASE WHEN DEPTID = ' ' THEN 'DEPTID IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
UNION
SELECT CASE WHEN PROJECT_ID =' ' THEN 'PROJECT_ID IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
)) WHERE ERROR <> ' '
WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
The above script results as below.
ERROR
BUSINESS_UNIT IS NULL
DEPTID IS NULL
I want the result as below.
ERROR
BUSINESS_UNIT IS NULL,DEPTID IS NULL
I am using ListAgg function but facing errors as below.Any help would be great.
SELECT LISTAGG(BUSINESS_UNIT, ';') WITHIN GROUP(ORDER BY USERID)
FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER'
GROUP BY BUSINESS_UNIT
Facing the error:
ORA-00923: FROM keyword not found where expected
00923. 00000 - "FROM keyword not found where expected"
*Cause:
*Action:
Error at Line: 47 Column: 43
You overcomplicated things. You don't need two unions and listagg at all. Simple use concatenation of case... when, write your select like here:
select case business_unit when ' ' then 'BUSINESS_UNIT IS NULL; ' end ||
case deptid when ' ' then 'DEPTID IS NULL; ' end ||
case project_id when ' ' then 'PROJECT_ID IS NULL; ' end as error
from ps_vi_emp_ts
where userid = 'JCOOPER' and action = 'E' and process_instance = '9852429'
demo
If your table has primary key then use it for update. Otherwise you can use merge with rowid. Or do it the way you did it if it worked for you, especially if there is only one row meeting criteria.
original data (image)
I want to display my data by concatenating several columns. But the data that appears less than perfect: there is a comma behind at the end of the concatenations, like the picture shows:
Here is the query that I created in oracle 10g
select id_pegawai,
whitelist_pembayaran||decode(whitelist_pembayaran,null,null,', ')||
whitelist_pemasang||decode(whitelist_pemasang,null,null,', ')||
whitelist_jenis_iklan||decode(whitelist_jenis_iklan,null,null) as whitelist,
blacklist_pembayaran||decode(blacklist_pembayaran,null,null,', ')||
blacklist_pemasang||decode(blacklist_pemasang,null,null,', ')||
blacklist_jenis_iklan||decode(blacklist_jenis_iklan,null,null) as blacklist
from verifikator order by id_verifikator desc
so you just want to remove the comma at the end? RTRIM it.
select id_pegawai,
rtrim(whitelist_pembayaran || decode(whitelist_pembayaran, null, null, ', ') ||
whitelist_pemasang || decode(whitelist_pemasang, null, null, ', ') ||
whitelist_jenis_iklan, ',') as whitelist,
rtrim(blacklist_pembayaran || decode(blacklist_pembayaran, null, null, ', ') ||
blacklist_pemasang || decode(blacklist_pemasang, null, null, ', ') ||
blacklist_jenis_iklan, ',') as blacklist
from verifikator
order by id_verifikator desc
Following is sample query.
CREATE PROCEDURE GetModel
(
#brandids varchar(100), -- brandid="1,2,3"
#bodystyleid varchar(100) -- bodystyleid="1,2,3"
)
AS
select * from model
where brandid in (#brandids) -- use a UDF to return table for comma delimited string
and bodystyleid in (#bodystyleid)
My requirement is that if #brandids or #bodystyleid is blank, query should return all rows for that condition.
Please guide me how to do this? Also suggest how to write this query to optimize performance.
You'll need dynamic SQL or a split function for this anyway, since IN ('1,2,3') is not the same as IN (1,2,3).
Split function:
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM (
SELECT Item = x.i.value('(./text())[1]', 'int') FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL
);
Code becomes something like:
SELECT m.col1, m.col2 FROM dbo.model AS m
LEFT OUTER JOIN dbo.SplitInts(NULLIF(#brandids, ''), ',') AS br
ON m.brandid = COALESCE(br.Item, m.brandid)
LEFT OUTER JOIN dbo.SplitInts(NULLIF(#bodystyleid, ''), ',') AS bs
ON m.bodystyleid = COALESCE(bs.Item, m.bodystyleid)
WHERE (NULLIF(#brandids, '') IS NULL OR br.Item IS NOT NULL)
AND (NULLIF(#bodystyleid, '') IS NULL OR bs.Item IS NOT NULL);
(Note that I added a lot of NULLIF handling here... if these parameters don't have a value, you should be passing NULL, not "blank".)
Dynamic SQL, which will have much less chance of leading to bad plans due to parameter sniffing, would be:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT columns FROM dbo.model
WHERE 1 = 1 '
+ COALESCE(' AND brandid IN (' + #brandids + ')', '')
+ COALESCE(' AND bodystyleid IN (' + #bodystyleid + ')', '');
EXEC sp_executesql #sql;
Of course as #JamieCee points out, dynamic SQL could be vulnerable to injection, as you'll discover if you search for dynamic SQL anywhere. So if you don't trust your input, you'll want to guard against potential injection attacks. Just like you would if you were assembling ad hoc SQL inside your application code.
When you move to SQL Server 2008 or better, you should look at table-valued parameters (example here).
if(#brandids = '' or #brandids is null)
Begin
Set #brandids = 'brandid'
End
if(#bodystyleid = '' or #bodystyleid is null)
Begin
Set #bodystyleid = 'bodystyleid'
End
Exec('select * from model where brandid in (' + #brandids + ')
and bodystyleid in (' + #bodystyleid + ')')