SQL SubQuery Error - sql

I would like to retrieve the data in the following sample.The following SQL will return two records.
SELECT -1 AS NUM
FROM TABLE
WHERE COMP_CODE = 'TEST'
AND (DETL_REMK = 'Rest Day'
OR SHFT_CODE = 'WK_PH')
AND RSRV_DATE_1 IS NOT NULL
AND RSRV_DATE_1 BETWEEN #TR_FR AND #TR_TO
AND EMPE_ID = 'TEST'
GROUP BY EMPE_ID,
RSRV_DATE_1
I would like to show the below.
ORG UNIT EMPE_ID FAM_NAME TMS_TYPE Qty
-----------------------------------------------------------------
'' '' '' Used -1
'' '' '' Used -1
So, I 'm trying to do like that the SQL statement. But I got the error
"Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
How to construct the right SQL. Please help me. Thanks in advance.
SELECT '' ORG_UNIT, '' EMPE_ID, '' FAM_NAME, 'Used' AS TMS_TYPE,
ISNULL(CAST(
(SELECT -1 AS NUM
FROM TABLE
WHERE COMP_CODE = 'TEST'
AND (DETL_REMK = 'Rest Day'
OR SHFT_CODE = 'WK_PH')
AND RSRV_DATE_1 IS NOT NULL
AND RSRV_DATE_1 BETWEEN #TR_FR AND #TR_TO
AND EMPE_ID = 'TEST'
GROUP BY EMPE_ID, RSRV_DATE_1)AS NVARCHAR(MAX)),0) QTY

If you're just hardcoding the values outside the subquery, you don't need a subquery to return the 2 rows, just do this:
SELECT '' ORG_UNIT, '' EMPE_ID, '' FAM_NAME, 'Used' AS TMS_TYPE, -1 AS QTY
FROM TABLE
WHERE COMP_CODE = 'TEST'
AND (DETL_REMK = 'Rest Day'
OR SHFT_CODE = 'WK_PH')
AND RSRV_DATE_1 IS NOT NULL
AND RSRV_DATE_1 BETWEEN #TR_FR AND #TR_TO
AND EMPE_ID = 'TEST'
GROUP BY EMPE_ID,
RSRV_DATE_1
The issue here is you're not referencing any columns from your table, just using it to produce an amount of rows. Please share the full issue and code, as I'm sure there is more to this that what you're asking.

You can try this one instead
SELECT '' ORG_UNIT, '' EMPE_ID, '' FAM_NAME, 'Used' AS TMS_TYPE, -1 as QTY
union all
SELECT '' ORG_UNIT, '' EMPE_ID, '' FAM_NAME, 'Used' AS TMS_TYPE, -1 as QTY

You would need to add Top 1 to your subquery, from the error you are getting, looks like the subquery is returning more than 1 row:
SELECT Top 1 -1 AS NUM
FROM TABLE
WHERE COMP_CODE = 'TEST'
AND (DETL_REMK = 'Rest Day',
OR SHFT_CODE = 'WK_PH')
AND RSRV_DATE_1 IS NOT NULL
AND RSRV_DATE_1 BETWEEN #TR_FR AND #TR_TO
AND EMPE_ID = 'TEST'
GROUP BY EMPE_ID, RSRV_DATE_1

Related

Optimizing a Postgres query

I have following query
SELECT
ca.sfid,
CASE WHEN p.Name IS NOT NULL THEN p.Name ELSE '' END AS Property,
CASE WHEN uc.Name IS NOT NULL THEN uc.Name ELSE '' END AS UnitofInterest,
CASE WHEN fp.Name IS NOT NULL THEN fp.Name ELSE '' END AS FloorplanofInterest,
CASE WHEN ca.Status IS NOT NULL THEN ca.Status ELSE '' END AS Status,
CASE WHEN ca.Origin IS NOT NULL THEN ca.Origin ELSE '' END AS Origin,
CASE
WHEN ca.IC_Call_Answered_by_AH__c = 'true' THEN 'Anyone Home'
ELSE 'Property'
END AS AnswerBy,
CASE WHEN ca.CaseNumber IS NOT NULL THEN ca.CaseNumber ELSE '' END AS CaseNumber,
CASE WHEN ca.Ad_Source_Type__c IS NOT NULL THEN ca.Ad_Source_Type__c ELSE '' END AS Source,
CONCAT(c.FirstName,' ',c.LastName) AS contactname,
CASE WHEN (c.Phone IS NOT NULL OR c.Phone != '' ) THEN c.Phone ELSE '' END AS Phone,
CASE WHEN c.MobilePhone IS NOT NULL THEN c.MobilePhone ELSE '' END AS Mobile,
CASE WHEN c.Email IS NOT NULL THEN c.Email ELSE '' END AS Email,
CASE WHEN c.most_recent_military_pay_grade__c IS NOT NULL THEN c.most_recent_military_pay_grade__c ELSE '' END AS MilitaryPayGrade,
CASE WHEN ca.Price_Quoted_1__c IS NOT NULL THEN ca.Price_Quoted_1__c ELSE '' END AS "price/termquoted",
CASE WHEN ca.Move_in_Date__c IS NOT NULL THEN to_char(ca.Move_in_Date__c AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY') ELSE '' END AS MoveinDate,
CASE WHEN ca.Of_Occupants__c::varchar IS NOT NULL THEN ca.Of_Occupants__c::varchar ELSE '' END AS "#occupants",
CASE WHEN ca.Bed_Count_Pref__c IS NOT NULL THEN ca.Bed_Count_Pref__c ELSE '' END AS BedCountPref,
CASE WHEN ca.Bath_Count_Pref__c IS NOT NULL THEN ca.Bath_Count_Pref__c ELSE '' END AS BathCountPref,
CASE WHEN ca.Pet_Count__c::varchar IS NOT NULL THEN ca.Pet_Count__c::varchar ELSE '' END AS "#pets",
CASE WHEN ca.Pet_Type__c IS NOT NULL THEN ca.Pet_Type__c ELSE '' END AS PetTypes,
CASE WHEN ca.Breed__c IS NOT NULL THEN ca.Breed__c ELSE '' END AS Breed,
CASE WHEN ca.Pet_Name__c IS NOT NULL THEN ca.Pet_Name__c ELSE '' END AS PetName,
CASE
WHEN (ca.Desired_Rent_Start__c IS NOT NULL AND ca.Desired_Rent_Range_End__c IS NOT NULL) THEN CONCAT(ca.Desired_Rent_Start__c,' - ',ca.Desired_Rent_Range_End__c)
ELSE ''
END AS DesiredRentRange,
CASE WHEN ca.Desired_Lease_length__c::varchar IS NOT NULL THEN ca.Desired_Lease_length__c::varchar ELSE '' END AS DesiredLeaseLength,
CASE WHEN ca.Reason_for_Moving__c IS NOT NULL THEN ca.Reason_for_Moving__c ELSE '' END AS ReasonforMoving,
CASE WHEN ca.Notes__c IS NOT NULL THEN ca.Notes__c ELSE '' END AS Notes,
CASE WHEN ca.Reasons_For_Not_Setting_a_Showing__c IS NOT NULL THEN ca.Reasons_For_Not_Setting_a_Showing__c ELSE '' END AS ReasonforNotSettingShowing,
CASE WHEN ca.CreatedDate IS NOT NULL THEN to_char(ca.CreatedDate AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY HH:MI AM') ELSE '' END AS "date/timeopened",
CASE
WHEN app.appointment_date__c IS NOT NULL THEN CONCAT(to_char(app.appointment_date__c AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY'),' ',app.from__c,'-',app.to__c)
ELSE ''
END AS "appointmentdate/time",
CASE WHEN ca.Yardi_Guest_Card_ID__c IS NOT NULL THEN ca.Yardi_Guest_Card_ID__c ELSE '' END AS PMSGuestCardID,
rank() OVER (PARTITION BY ca.contactid, ca.property_of_interest__c ORDER BY ca.createddate DESC)
FROM
salesforce.Case ca
INNER JOIN salesforce.Contact c on ca.ContactId = c.sfid AND c.accountId = ca.accountId
LEFT JOIN salesforce.Appointment__c app ON ca.sfid = app.case__c
LEFT JOIN salesforce.Property__c p ON p.sfid = ca.Property_of_Interest__c AND p.account__c = ca.accountId
LEFT JOIN salesforce.Floor_Plan__c fp ON ca.Floor_Plan_of_Interest__c = fp.sfid AND fp.account__c = ca.accountId
LEFT JOIN salesforce.Unit__c uc ON ca.Unit_of_Interest__c = uc.sfid AND uc.account__c = ca.accountId
WHERE
ca.Guest_Card_Status__c = 'Sent via Workflow'
AND ca.accountId = '001i000000ESO3CAAX'
AND to_char(to_char(ca.createddate AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific','YYYY-MM-DD HH24:MI:SS')::date, 'YYYY-MM-DD') BETWEEN '2016-06-02' AND '2016-07-02'
AND to_char(c.Last_Activity__c AT TIME ZONE 'US/Pacific', 'YYYY-MM-DD') BETWEEN '2016-03-04' AND '2016-07-02'
AND ( ca.Status IN ( 'Inquiry', 'Showing Set', 'Showing Completed', 'Application Pending', 'Resident' ) )
AND ( ca.IC_Call_Answered_by_AH__c IN ( 'false', 'true' ) )
AND ( ca.origin IN ( 'Phone', 'Email', 'Voicemail', 'Chat', 'Walk-In', 'Web' ) OR ca.origin IS NULL OR ca.origin = '' ) LIMIT 20 OFFSET 0
And following is the query plan for it
We have indexes on following columns:
AccountId
createddate
Status
Origin
Using PostgreSQL.
But query is taking long time to run. Can you please suggest any optimization in it?
Thanks
Without knowing much about your data set and being unable to read the screenshot of the query plan, I see a couple easy improvements you can make.
First, your use of the indexed columns accountId, status, and origin columns is fine. However, your usage of the createddate column is flawed. By converting the column to a string and then performing a comparison after it has been converted to a string, you are no longer using the index -- Postgres must perform a full scan and run two costly to_char conversions.
Qualify on your createddate column with a comparison native to the datatype of the column.
For example, if the datatype of createdate is timestamp, then you could qualify on it like this:
AND ca.createdate BETWEEN '2016-06-02'::timestamp AND '2016-07-02'::timestamp
This will use the index and it will perform much better.
Second, make sure that you've created one index that uses all four of the columns you've listed. If you have created four separate indexes for each of those columns, then you are not realizing the full performance gains possible from indexing. An index that uses all four of the columns will allow Postgres to progressively narrow down the result set with each column. If you have four separate indexes, then Postgres can only narrow down the result set with one column.

SQL CASE wrong output

I have this weird encounter using CASE in sql 2014.
This is my query:
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE dbo.GetFunctionAge(C.Birthdate)
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
this is the output:
Here is the GetFunctionAge function if you might ask.
IF EXISTS (
SELECT *
FROM dbo.sysobjects
WHERE ID = OBJECT_ID(N'[dbo].[GetFunctionAge]') AND
xtype in (N'FN', N'IF', N'TF'))
DROP FUNCTION [dbo].[GetFunctionAge]
GO
CREATE FUNCTION [dbo].[GetFunctionAge](#BirthDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE #Age INT
IF(#BirthDate = '1753-01-01 00:00:00.000')
BEGIN
SET #Age = 0
END
ELSE
BEGIN
SET #Age = DATEDIFF(hour,#BirthDate,GETDATE())/8766
END
RETURN #Age
END
GO
Question:
Why is Column Age in my output is 0which should be ''?
I added (No column name) to show that its output is 0 so my expected output base from my case condition is '' not 0
I didn't receive any error regarding inconsistency of data so why is case behaving like that?
Thanks for those who could clarify this to me.
SELECT
(CASE
WHEN a.ageint = 0 THEN ''
ELSE cast(a.ageint as varchar(3))
END) AS Age
, a.ageint
, c.Birthdate
FROM Client as C
CROSS APPLY (
SELECT
ISNULL(dbo.GetFunctionAge(C.Birthdate), 0) AS ageint
) AS a
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
;
You can cast it into varchar so you can return ' '.
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE Cast(dbo.GetFunctionAge(C.Birthdate) as varchar(5))
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
But If you wish to remain your Age column in data type int.
You could just use NULL instead of ' '

Case statement for 'where [value] is not null'

I've seen plenty of SO questions where someone is testing for a NULL value within a case statement, but nothing of the nature of this question. I want the return of the case statement to be a 'is not null' expression for a where clause.
This is what I have:
INSERT INTO table1 (Id) (
SELECT DISTINCT AId AS Id
FROM table2 As t2
INNER JOIN table3
ON (
...
)
WHERE CASE
WHEN test_value <> '' THEN (another_value IS NOT NULL)
END
)
This gives the error:
Incorrect syntax near the keyword 'is'.
In short, if the test value is not empty-string, then I do not want rows with another_value=NULL in my table1.
My program needs to pass 2 cases
Case 1:
Row# test_value another_value ....
1 'tst' '919'
2 'tst' NULL
ONLY ROW ONE SHOULD BE INSERTED
Case 2:
Row# test_value another_value ....
1 '' '919'
2 '' NULL
BOTH ROWS SHOULD BE INSERTED
Try this:
WHERE ((isnull(test_value,'') <> '' and ISNULL(another_value,'') <> '') OR ISNULL(test_value,'') = '')
You can do something like that:
WHERE CASE
WHEN test_value <> '' AND another_value IS NOT NULL THEN another_value
END

Execution of sql query takes a long time

I have this problem with my query that it is really slow. I am using MSSQL server 2008 and have 3 DB with hundreds of sample data in it. The query will return a name and value and a computed percentage based on the 3 DBs. But the query I have will take almost 10mins to execute which is really a long time to take. I am still learning SQL and still not that good so I think the query I have is not using the best practice and not organized. Can anybody point to me where or how I can improve my query to run faster?
SELECT data.Ret,
case
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') and (data.rowid % 50) = 0 then (data.rowid / 50)-1
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') then (data.rowid / 50)
else 0 end as batchStore
,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal,data.Version
,data.A_Percent,data.T_Percent,data.F_Percent
from
(
SELECT report.Ret,
CASE when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5')
then row_number() over (PARTITION BY report.Ret,report.Version order by report.Ret, report.MajorName)
else 0 end as rowid
,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal,report.Version
,report.GTotal_A,report.GTotal_T,report.GTotal_F
,ISNULL(sum(report.Abn) / NULLIF(cast(report.GTotal_A as decimal),0),0) * 100 as A_Percent
,ISNULL(sum(report.Trn) / NULLIF(cast(report.GTotal_T as decimal),0),0) * 100 as T_Percent
,ISNULL(sum(report.Fld)/ NULLIF(cast(report.GTotal_F as decimal),0) * 100,0) as F_Percent
From
(
Select
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MajorName,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MinorName,
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MajorVal,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MinorVal,
csl.Cust_Name as Ret,l.SWVersion as Version
,d.Abn,d.Trn,d.Fld,data.GTotal_A ,data.GTotal_T,data.GTotal_F
From db_mon.dbo.CustSL csl
join db_tax.dbo.vwLane l
on (l.externalid = csl.custsl_id)
join db_mon.dbo.DaySummary dy
on (dy.Str = csl.s_name and dy.Lne = csl.l_name and year(dy.day_stamp) = year(#time_start_date) and year(dy.day_stamp) =year(#time_end_date))
Left Outer Join
(
Select a.id As AttributeId, a.attribute_name As AttributeName,
(Case When a.attribute_value_type = 'string' Then ea.string_value
Else (Case When a.attribute_value_type = 'integer' Then cast(ea.integer_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'date' Then cast(ea.date_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'boolean' Then cast(ea.boolean_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'entity' Then cast(ea.ref_entity_id as nvarchar(100)) Else null End)
End)
End)
End)
End) As AttributeValue,
e.id As EntityId
From db_tax.dbo.entity_type et
Inner Join db_tax.dbo.entity As e on et.id = e.entity_type_id
Inner Join db_tax.dbo.entity_attribute As ea on e.id = ea.entity_id
Inner Join db_tax.dbo.attribute As a on ea.attribute_id = a.id
WHERE et.entity_type_name in ('Sticker','Label') And
a.id = (case WHEN #attribute_id = '' then 1 else cast(#attribute_id as int) end)
) AS attrib
On attrib.EntityId = l.L_Id
inner join db_mon.dbo.DaySummary d
on (csl.Cust_Name = d.Ret and csl.s_name = d.stckr and csl.l_name = d.label and l.SWVersion = d.Version)
join (
SELECT Ret,version,sum(Abn) as GTotal_A,sum(Trn) as GTotal_T,sum(Fld) as GTotal_F
from db_mon.dbo.DaySummary
where day_stamp >= #time_start_date and day_stamp <=#time_end_date
GROUP BY Ret,version
) data
on (d.Ret = data.Ret and l.SWVersion = data.Version)
WHERE (CHARINDEX(',' + CONVERT(VARCHAR,l.S_Id) + ',','xxx,' + #entities + ',xxx')>0 OR CHARINDEX(',' + CONVERT(VARCHAR,l.L_Id) + ',','xxx,' + #entities + ',xxx')>0)
and d.day_stamp >= #time_start_date
and d.day_stamp <=#time_end_date
) As report
Group By report.Ret,report.Version,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal
,report.GTotal_A,report.GTotal_T,report.GTotal_F
)data
order By data.Ret,data.Version,batchStore,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal
Does using a lot of join causes the slow execution?
SUB Select queries will always be slower then proper joins.
You are running 3 sub selects deep. This is going to impact your performance regardless of changing indexes etc.
You need to rewrite the whole thing to stop using sub selects.

Sql Server conditional Contains for free text search handling of Null parameter

I have been struggling for quite some time to get this query going.
In short my query searches by fileno and/or searchfield
DECLARE #pSearchFor AS NVARCHAR(100);
-- I am here testing with null value, ' ' , or seperate words
SET #pSearchFor = null -- '"marsa" and "mosta"';
IF ISNULL(#pSearchFor,'') = '' SET #pSearchFor = '""' ;
declare #fileNo nvarchar(50) = 'e/e'
select top 1000 r.FileId, r.FileNo, fs.SearchField, #pSearchFor
from regfile as r
left outer join FileSearchFields as fs on r.FileId = fs.FileID
where r.FileNo like
CASE
WHEN Len(#fileno) > 1 THEN '%'+#fileNo+'%'
ELSE r.FileNo
END
AND
1 =
CASE WHEN ISNULL(#pSearchFor, '') = '' THEN 1 ELSE 0 END
or CONTAINS(fs.SearchField, #pSearchFor)
I am getting nothing returned if #pSearchFor is null otherwise works great.
I need to return all instances if a null
One possible solution might be to call 2 seperate sps or use if /else but probably exists a better method.
I really do appreciate your help!
First you set #pSearchFor to "":
IF ISNULL(#pSearchFor,'') = '' SET #pSearchFor = '""' ;
That means this will never return 1:
CASE WHEN ISNULL(#pSearchFor, '') = '' THEN 1 ELSE 0 END
You need to either use a different variable, or use the same type of CASE expression in the select list, instead of changing the value from NULL to "".
SELECT TOP 1000 r.FileId, r.FileNo, fs.SearchField,
CASE WHEN COALESCE(#pSearchFor, '') = '' THEN '""' ELSE #pSearchFor END
Also you use SELECT TOP but no ORDER BY ... if you want a subset, don't you care which subset you get?
I have solved the problem. Maybe this may be of some help to others!
This is a snippet of my stored procedure.
#fileNo nvarchar(50) = null ,
#fields nvarchar(100) = '""',`enter code here`
#datefrom date = null,
#dateto date = null,
...
AS`enter code here`
BEGIN
if (#fields = null or LEN(#fields) < 1 ) set #fields = '""'
select top 1000 r.*,
(CASE
WHEN fs.SearchField IS NULL THEN CONVERT(NVarChar(1),'')
ELSE CONVERT(NVarChar(MAX),fs.SearchField)
END) AS [Search]
from regfile as r
left outer join FileSearchFields as fs on r.FileId = fs.FileID
where r.FileNo like
CASE
WHEN Len(#fileno) > 1 THEN '%'+#fileNo+'%'
ELSE r.FileNo
END
and
r.Date between
CASE
WHEN #datefrom != '' THEN #datefrom
ELSE '1900-1-1'
END
and
CASE
WHEN #dateto != '' THEN #dateto
ELSE '9999-1-1'
END
and
((LEN(#fields) > 2 and contains(fs.SearchField,#fields))or (LEN(#fields) <= 2))
--NB: <= 2 as we have added the "" characters in #fields!
end