SQL Subquery Questions - mysql

I am trying to combine these 2 queries in such a way to determine who the PI is that owns equipment (>$100K value). I have the ability to find all the equipment one PI owns that is greater then 100k. I also have the ability to see all the PIs. I just cannot get these 2 queries to combine. I have tried with a WHERE subquery and an EXIST subquery. I want to be able to find all the equipment (matched with its PI owner) where the PI exists in query #2.
Query #1 for finding equipment of a specific PI
select Account_No,Inventory_No,Building_No,Room_No,CDDEPT,Location,Normalized_MFG,Manufacturer_Name,Normalized_Model,Name,Serial_Code,CONCAT( '$', FORMAT( Cost, 2 ) ) as Cost, Equipment_Inventory_Normalized.Active
from Temp_Equipment_Inventory.Equipment_Inventory_Normalized, `paul`.`ROOM`, `paul`.`BLDG`, `paul`.`LABORATORY`, `paul`.`PERSON`
where (`PERSON`.`ID` = `LABORATORY`.`PI_ID` OR `PERSON`.`ID` = `LABORATORY`.`SUPV_ID`)
AND `LABORATORY`.`RM_ID` = `ROOM`.`ID`
AND `LABORATORY`.`ACTIVE` = '1'
AND `ROOM`.`BLDG_ID` = `BLDG`.`ID`
AND ((
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Building_No
AND Equipment_Inventory_Normalized.Actual_Building IS NULL
AND (`BLDG`.`BLDGNUM` != '1023' AND `LABORATORY`.`OTHER_LEVEL` != '1' AND `ROOM`.`RMNUM` != '0199')
)OR (
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Actual_Building AND
(`BLDG`.`BLDGNUM` != '1023' AND `LABORATORY`.`OTHER_LEVEL` != '1' AND `ROOM`.`RMNUM` != '0199')
))
AND ((
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Room_No
AND Equipment_Inventory_Normalized.Actual_Room IS NULL
)OR (
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Actual_Room
))
AND Equipment_Inventory_Normalized.Active !=0
AND SurplusPending != '1'
AND Cost >= 100000
AND `PERSON`.`CANNUM`='810010787'
Query 2 that finds all the PIs
select distinct i.CAN
from CGWarehouse.CCGV10WC w
inner join CGWarehouse.CCGV10IC i
on w.PROJECT_NUMBER=i.SPONSORED_PROJECT
and w.SEQUENCE_NUMBER=i.PROJECT_SEQUENCE
where w.STATUS='A'
and i.PRIN_INVEST_CODE='Y'
and i.DEL_CODE!='Y'
and i.CAN IS NOT NULL

Perhaps you're looking for the IN keyword in your WHERE clause?
Forgive me, but I had to clean up the formatting of your query a little...it's kinda my OCD thing:
SELECT
Account_No,
Inventory_No,
Building_No,
Room_No,
CDDEPT,
Location,
Normalized_MFG,
Manufacturer_Name,
Normalized_Model,
Name,
Serial_Code,
CONCAT('$', FORMAT( Cost, 2 )) AS Cost,
Equipment_Inventory_Normalized.Active
FROM
Temp_Equipment_Inventory.Equipment_Inventory_Normalized a,
`paul`.`ROOM`,
`paul`.`BLDG`,
`paul`.`LABORATORY`,
`paul`.`PERSON`
WHERE
(`PERSON`.`ID` = `LABORATORY`.`PI_ID` OR `PERSON`.`ID` = `LABORATORY`.`SUPV_ID`)
AND `LABORATORY`.`RM_ID` = `ROOM`.`ID`
AND `LABORATORY`.`ACTIVE` = '1'
AND `ROOM`.`BLDG_ID` = `BLDG`.`ID`
AND (
(
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Building_No
AND Equipment_Inventory_Normalized.Actual_Building IS NULL
AND `BLDG`.`BLDGNUM` != '1023'
AND `LABORATORY`.`OTHER_LEVEL` != '1'
AND `ROOM`.`RMNUM` != '0199'
) OR (
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Actual_Building
AND `BLDG`.`BLDGNUM` != '1023'
AND `LABORATORY`.`OTHER_LEVEL` != '1'
AND `ROOM`.`RMNUM` != '0199'
)
)
AND (
(
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Room_No
AND Equipment_Inventory_Normalized.Actual_Room IS NULL
) OR (
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Actual_Room
)
)
AND Equipment_Inventory_Normalized.Active !=0
AND SurplusPending != '1'
AND Cost >= 100000
AND `PERSON`.`CANNUM` IN ( /* this assumes that the `PERSON`.`CANNUM` column matches up with the CGWarehouse.CCGV10IC.CAN column */
SELECT DISTINCT i.CAN
FROM
CGWarehouse.CCGV10WC w
INNER JOIN CGWarehouse.CCGV10IC i ON w.PROJECT_NUMBER=i.SPONSORED_PROJECT AND w.SEQUENCE_NUMBER=i.PROJECT_SEQUENCE
WHERE
w.STATUS='A'
AND i.PRIN_INVEST_CODE='Y'
AND i.DEL_CODE!='Y'
AND i.CAN IS NOT NULL
)

Related

MySQL Multiple Case When Exists Statement

I have two tables. Let's call it: SEATS and SEAT_ALLOCATION_RULE table.
Below are the table schema:
CREATE TABLE IF NOT EXISTS `SEATS` (
`SeatID` int(11) NOT NULL AUTO_INCREMENT,
`SeatName` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`SeatID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
INSERT INTO `SEATS` (`SeatID`, `SeatName`) VALUES
(1, 'Super VIP'),
(2, 'VIP'),
(3, 'Business'),
(4, 'Economy'),
(5, 'Standing');
CREATE TABLE IF NOT EXISTS `SEAT_ALLOCATION_RULE` (
`SeatID` int(11) NOT NULL DEFAULT '0',
`Origin` varchar(50) NOT NULL DEFAULT '0',
`Destination` varchar(50) NOT NULL DEFAULT '',
`Passenger_Type` varchar(25) NOT NULL DEFAULT '',
PRIMARY KEY (`SeatID`,`Origin`,`Destination`,`Passenger_Type`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `SEAT_ALLOCATION_RULE` (`SeatID`, `Origin`, `Destination, `Passenger_Type`) VALUES
(1, 'Malaysia','',''),
(2, 'Malaysia','Singapore',''),
(3, 'Malaysia','Singapore','Senior_Citizen'),
(4, 'Bangkok','Japan','Student'),
(5, 'Cambodia','China','Senior_Citizen');
SEAT_ALLOCATION_RULE table determines which seat should a passenger be assigned to based on the following order in priority:
1. Origin, destination, and passenger_type match
2. Origin and destination match
3. Origin match
It means that if all the fields (origin, destination, and passenger_type) match, it should take higher priority than if it is just two fields match and so on. If a column is empty, it is considered as unspecified and hence has lower priority. So, for example:
If the Origin is Malaysia, Destination is Singapore, and Passenger_Type is Senior_Citizen, it should return seatID 3
If the Origin is Malaysia, Destination is Singapore, and Passenger_Type is Student, it should return seatID 2 (since it only match Origin and Destination)
If the Origin is Malaysia, Destination is US, and Passenger_Type is Student, it should return seatID 1 (since it only match Origin).
Now, based on the rules above, if the origin is Malaysia, destination is Singapore, and Passenger_Type is student, the query to return seatID is as follow:
SELECT s.SeatID, s.SeatName
FROM SEATS s
WHERE
CASE WHEN EXISTS(
select 1
from SEAT_ALLOCATION_RULE r
where s.SeatID = r.SeatID
AND r.Origin = 'Malaysia'
AND r.Destination = 'Singapore'
AND r.Passenger_Type='Student') Then 1
WHEN EXISTS(
select 1
from SEAT_ALLOCATION_RULE r
where s.SeatID = r.SeatID
AND r.Origin = 'Malaysia'
AND r.Destination = 'Singapore'
AND r.Passenger_Type='') Then 1
WHEN EXISTS(
select 1
from SEAT_ALLOCATION_RULE r
where s.SeatID = r.SeatID
AND r.Origin = 'Malaysia'
AND r.Destination = ''
AND r.Passenger_Type='') Then 1 END
However, the query above does not work as it will return seatID 1 and 2, but the expected output is only seatID 2 (since origin and destination matches and it takes higher precedence). Can someone help to correct my SQL query?
This should do the trick:
select seatid
from seat_allocation_rule sar
order by ((sar.origin = :origin) << 2) + ((sar.destination = :destination) << 1) + (sar.passenger_type = :passenger_type) desc,
((sar.origin <> '') << 2) + ((sar.destination <> '') << 1) + (sar.passenger_type <> '') asc
limit 1
To understand how:
create table testcase (
origin varchar(255),
destination varchar(255),
passenger_type varchar(255),
expected_seat int(11)
);
insert into testcase values ('Malaysia','Singapore','Senior_Citizen',3),
('Malaysia','Singapore','Student',2),
('Malaysia','US','Student',1);
select * from (
select tc.*,
sar.seatid,
case when sar.seatid = tc.expected_seat then 'Y' else '-' end as pass,
((sar.origin = tc.origin) << 2)
+ ((sar.destination = tc.destination) << 1)
+ ((sar.passenger_type = tc.passenger_type) << 0) as score,
((sar.origin <> '') << 2)
+ ((sar.destination <> '') << 1)
+ ((sar.passenger_type <> '') << 0) as priority
from seat_allocation_rule sar
cross join testcase tc
) x order by expected_seat desc, score desc, priority asc;
This fixes the existing SQL:
SELECT DISTINCT s.SeatID, s.SeatName
FROM SEATS s
LEFT JOIN SEAT_ALLOCATION_RULE r ON r.SeatID = s.SeatID
AND r.Origin = 'Malaysia'
AND (
(r.Destination = 'Singapore' AND r.Passenger_Type IN ('Student', ''))
OR
(r.Destination = '' AND r.Passenger_Type = '')
)
WHERE r.SeatID IS NOT NULL
But it's only a partial solution, and it's hand-coding logic you really want to apply based solely on the data.
A complete solution will use hypothetical inputs for your passenger's ticket info to produce all eligible seats. This is a great use of lateral joins/apply, which are sadly lacking in MySql (all of their major competitors have had these for at least two release cycles, along with other gems that are absent from the current MySql release like windowing functions, ctes, full joins... I could go on). Here's how I'd do it in Sql Server:
SELECT p.PassengerID, s.SeatID, s.SeatName
FROM Passenger p
CROSS APPLY (
SELECT TOP 1 r.SeatID
FROM SEAT_ALLOCATION_RULE r
WHERE COALESCE(NULLIF(r.Origin, ''),p.Origin) = p.Origin
AND COALESCE(NULLIF(r.Destination,''), p.Destination) = p.Destination
AND COALESCE(NULLIF(r.Passenger_Type,''),p.Passenger_Type) = p.Passenger_Type
ORDER BY
CASE WHEN r.Origin <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Destination <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Passenger_Type <> '' THEN 1 ELSE 0 END DESC
) r
INNER JOIN SEATS s ON s.SeatID = r.SeatID
WHERE p.PassengerID = /* passenger criteria here */
I know the Sql Server solution isn't much immediate help to you, but perhaps it will suggest a better MySql solution.
Without APPLY, the only way I know to do this is to first compute the MAX() match count for your passengers (how many parts of the rules match):
SELECT p.PassengerID,
MAX(CASE WHEN r.Origin <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Destination <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Passenger_Type <> '' THEN 1 ELSE 0 END) AS MatchCount
FROM Passenger p
INNER JOIN SEAT_ALLOCATION_RULE r ON COALESCE(NULLIF(r.Origin, ''),p.Origin) = p.Origin
AND COALESCE(NULLIF(r.Destination,''), p.Destination) = p.Destination
AND COALESCE(NULLIF(r.Passenger_Type,''),p.Passenger_Type) = p.Passenger_Type
GROUP BY p.PassengerID
And then use that to filter down to results that have the same number of matches:
SELECT p
FROM Passenger p
INNER JOIN ( /* matchecounts */
SELECT p.PassengerID,
MAX(CASE WHEN r.Origin <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Destination <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Passenger_Type <> '' THEN 1 ELSE 0 END) AS MatchCount
FROM Passenger p
INNER JOIN SEAT_ALLOCATION_RULE r ON COALESCE(NULLIF(r.Origin, ''),p.Origin) = p.Origin
AND COALESCE(NULLIF(r.Destination,''), p.Destination) = p.Destination
AND COALESCE(NULLIF(r.Passenger_Type,''),p.Passenger_Type) = p.Passenger_Type
GROUP BY p.PassengerID
) m ON m.PassengerID = p.PassengerID
INNER JOIN SEAT_ALLOCATION_RULE r ON COALESCE(NULLIF(r.Origin, ''),p.Origin) = p.Origin
AND COALESCE(NULLIF(r.Destination,''), p.Destination) = p.Destination
AND COALESCE(NULLIF(r.Passenger_Type,''),p.Passenger_Type) = p.Passenger_Type
INNER JOIN SEATS s ON s.SeatID = r.SeatID
WHERE m.MatchCount =
(CASE WHEN r.Origin <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Destination <> '' THEN 1 ELSE 0 END
+ CASE WHEN r.Passenger_Type <> '' THEN 1 ELSE 0 END)
AND p.PassengerID = /* Passenger criteria here */
Which repeats a lot of code as well as effort in the DB, and is not very efficient. You can repeat the passenger criteria in the nested query, but that would only help a little. This option might also return multiple records for a passenger if they match two rules equally, though you can solve this easily enough with a GROUP BY expression.
In either case, note you can improve performance and simplify code by using actual NULL values instead of empty strings for missing parts of the SEAT_ALLOCATION_RULE table.

Output of 3 queries

Got this 3 in 1 query:
SELECT * FROM
(
SELECT mesures.date j, AVG(mesures.valeur) maxi
FROM mesures
JOIN plages_horaire ON mesures.id_plage = plages_horaire.id_plage
WHERE MONTH(mesures.date) = '9' AND YEAR(mesures.date) = '2016' AND mesures.code_station = 'P02SE' AND mesures.id_crit = '1' AND mesures.id_type = '1'
GROUP BY mesures.date
) maxi
,
(
SELECT AVG(mesures.valeur) mini
FROM mesures
JOIN plages_horaire ON mesures.id_plage = plages_horaire.id_plage
WHERE MONTH(mesures.date) = '9' AND YEAR(mesures.date) = '2016' AND mesures.code_station = 'P02SE' AND mesures.id_crit = '1' AND mesures.id_type = '2'
GROUP BY mesures.date
) mini
,
(
SELECT AVG(mesures.valeur) moy
FROM mesures
JOIN plages_horaire ON mesures.id_plage = plages_horaire.id_plage
WHERE MONTH(mesures.date) = '9' AND YEAR(mesures.date) = '2016' AND mesures.code_station = 'P02SE' AND mesures.id_crit = '1' AND mesures.id_type = '3'
GROUP BY mesures.date
) moy
GROUP BY j
Problem is that I get what I want excepting values of the 2 last columns are the same at every rows:
query output
I believe it's because of the GROUP BY.
From what I can see from your query, you don't need the plage_horaire table. You can also simplify the logic greatly by using conditional aggregation:
SELECT m.date,
AVG(CASE WHEN m.id_type = 1 THEN m.valeur END) maxi,
AVG(CASE WHEN m.id_type = 2 THEN m.valeur END) mini,
AVG(CASE WHEN m.id_type = 3 THEN m.valeur END) maxmoy,
FROM mesures m
WHERE MONTH(m.date) = 9 AND YEAR(m.date) = 2016 AND
m.code_station = 'P02SE' AND m.id_crit = 1 AND m.id_type IN (1, 2, 3)
GROUP BY m.date ;
Notice that I also removed the quotes from the numeric constants. MONTH() and YEAR() return numbers, so quotes are not appropriate. I am guessing that the ids are numeric as well.

How to write condition for subquery alias if having null value

Here is my query,
SELECT
`h`.`hotel_id`,
(
SELECT COUNT(room_id)
FROM
`abserve_hotel_rooms` AS `rm`
WHERE
`rm`.`adults_count` >= "1" AND `rm`.`room_count` >= "1" AND "Available" = IF(
check_in_time = '2016-03-15',
'Unavailable',
(
IF(
'2016-03-15' > check_in_time,
(
IF(
'2016-03-15' < check_out_time,
'Unavailable',
'Available'
)
),
(
IF(
'2016-03-22' > check_in_time,
'Unavailable',
'Available'
)
)
)
)
) AND `room_prize` BETWEEN '174' AND '600' AND `rm`.`hotel_id` = `h`.`hotel_id`
) AS `avail_room_count`,
(
SELECT MIN(room_prize)
FROM
`abserve_hotel_rooms` AS `rm`
WHERE
`rm`.`adults_count` >= "1" AND `rm`.`room_count` >= "1" AND "Available" = IF(
check_in_time = '2016-03-15',
'Unavailable',
(
IF(
'2016-03-15' > check_in_time,
(
IF(
'2016-03-15' < check_out_time,
'Unavailable',
'Available'
)
),
(
IF(
'2016-03-22' > check_in_time,
'Unavailable',
'Available'
)
)
)
)
) AND `room_prize` BETWEEN '174' AND '600' AND `rm`.`hotel_id` = `h`.`hotel_id`
) AS `min_val`
FROM
`abserve_hotels` AS `h`
WHERE
1 AND `city` = "madurai" AND `country` = "india"
It totally return one column values from my table abserve_hotels which is hotel_id with extra two alias columns such as avail_room_count and min_val..
And I wrote those in a subquery..
Here I have to check a condition WHERE min_val IS NOT NULL .i.e; if min_val having NULL value I have to restrict it
How can I do this..
And this is my table
hotel_id avail_room_count min_val
1 0 NULL
2 0 NULL
Here I need to restrict these NULL values..
Someone please help me ..
Add a HAVING clause at the end:
HAVING min_val IS NOT NULL
The new query after WHERE looks like:
WHERE
1 AND `city` = "madurai" AND `country` = "india"
HAVING min_val IS NOT NULL
Your query is overly complex and can be much simplified:
The two correlated sub queries are exactly the same, except for the SELECT list (MIN versus COUNT), so they could be combined into one;
The aggregation done by the sub query can be done in the main query;
The condition for checking availability can be written much shorter.
In fact, you can do all of what you need with the following query:
SELECT h.hotel_id,
COUNT(rm.room_id) as avail_room_count,
MIN(rm.room_prize) AS min_val
FROM abserve_hotels AS h
INNER JOIN abserve_hotel_rooms AS rm
ON rm.hotel_id = h.hotel_id
WHERE h.city = "madurai"
AND h.country = "india"
AND rm.adults_count >= 1
AND rm.room_count >= 1
AND rm.room_prize BETWEEN 174 AND 600
AND ( rm.check_in_time >= '2016-03-22'
OR rm.check_out_time <= '2016-03-15'
OR rm.check_in_time IS NULL)
GROUP BY h.hotel_id
Because the INNER JOIN requires at least one match, you can already be sure that min_val will never be NULL.
The check for availability is just as simple as:
( rm.check_in_time >= '2016-03-22'
OR rm.check_out_time <= '2016-03-15'
OR rm.check_in_time IS NULL)
The three parts of that condition mean:
The reservation for this room is future and does not overlap with this week;
The reservation for this room is in the past, the room is free today at the latest;
The room has no known reservation.
In all three cases the room is available for reservation for the concerned week.

How can I limit the number of results of a specific part of an SQL query?

Can you see a way in the following SQL call to limit the number of results of just this specific part:
OR (u1 != '2' AND u2 != '2' AND u3 != '2' AND m.membership_id = 1 AND m.aff IN (SELECT id FROM members WHERE id != 2 AND membership_id = 1 OR jv > 0)))
I like to limit that number of matches to a exact number, e.g. 150
The full SQL is:
SELECT DISTINCT mid, did FROM product_access, members AS m
WHERE mid = m.id AND m.active = 1
AND m.suspended = 0
AND (u1 = '2' OR u2 = '2' OR u3 = '2' OR (u1 != '2' AND u2 != '2' AND u3 != '2' AND m.membership_id = 1 AND m.aff IN (SELECT id FROM members WHERE id != 2 AND membership_id = 1 OR jv > 0))) GROUP BY mid
So, the result should include all where u1 = '2', all where u2 = '2', all where u3 = '2', but just 150 where:
(u1 != '2' AND u2 != '2' AND u3 != '2' AND m.membership_id = 1 AND m.aff IN (SELECT id FROM members WHERE id != 2 AND membership_id = 1 OR jv > 0))
You can always make a subquery from every single part of your query and have it LIMITed to the n TOPmost entries.
From what I understand, something like this should suffice:
SELECT mid, did FROM(
SELECT DISTINCT mid, did FROM product_access, members AS m
WHERE mid = m.id AND m.active = 1
AND m.suspended = 0
AND (u1 = '2' OR u2 = '2' OR u3 = '2')
UNION SELECT TOP 150 DISTINCT mid, did FROM product_access, members AS m
WHERE mid = m.id AND m.active = 1
AND m.suspended = 0
AND (u1 != '2' AND u2 != '2' AND u3 != '2' AND m.membership_id = 1 AND m.aff IN (SELECT id FROM members WHERE id != 2 AND membership_id = 1 OR jv > 0))
) GROUP BY mid
If SQL SERVER Then use TOP , If MY SQL Then use LIMIT.
SQL-Server
SELECT TOP 10 * FROM MyTable;
My SQL
SELECT * FROM MyTable LIMIT 10;

Tuning Slow Performing Queries

I have a query which is taking too long to execute.
I used database tuning advisor to check this query and it suggested some missing indexes and statistics. The problem is I can't create missing index and statistics on those tables because it will slowdown insert/update and affect other scripts. They can't sacrifice their scripts performance because of my query.
Without the help of DTA or disturbing other scripts how do I have to tune my query? Can i break it into small pieces? If so, how?
INSERT INTO #val
SELECT lid.orgid,
lid.periodid,
lid.sourceid,
lid.statementtypecode,
lid.financialsbucketid,
lid.statementcurrencycodeiso,
lid.lineitemid,
lll.financialconceptidglobal,
lid.physicalmeasureid,
CASE
WHEN EXISTS(SELECT TOP 1 '1'
FROM trf.dbo.lineitemfundbdescription LIFD(nolock)
WHERE lll.orgid = lifd.orgid
AND lll.lineitemid = lifd.lineitemid) THEN
(SELECT lifd.lineitemshortdescription
FROM trf.dbo.lineitemfundbdescription LIFD(nolock)
WHERE lll.orgid = lifd.orgid
AND lll.lineitemid = lifd.lineitemid)
ELSE lll.lineitemname
END AS LineItemName,
( CASE
WHEN ( lid.reportedcurrencycodeiso IS NOT NULL
AND fc.iscurrencydependent = 1
AND
lid.statementcurrencycodeiso <> lid.reportedcurrencycodeiso
AND fc.isflowitem = 1 ) THEN
lid.lineiteminstancevalue *
cds.dbo.Exrate(lid.reportedcurrencycodeiso, lid.statementcurrencycodeiso, p.periodenddate)
WHEN ( lid.reportedcurrencycodeiso IS NOT NULL
AND fc.iscurrencydependent = 1
AND lid.statementcurrencycodeiso <> lid.reportedcurrencycodeiso
AND fc.isflowitem = 0
AND p.periodlengthunitcode = 'M' ) THEN lid.lineiteminstancevalue
*
cds.dbo.Getaveragefxrate(lid.reportedcurrencycodeiso, lid.statementcurrencycodeiso,
Dateadd("MONTH", -p.periodlength, p.periodenddate), p.periodenddate)
WHEN ( lid.reportedcurrencycodeiso IS NOT NULL
AND fc.iscurrencydependent = 1
AND lid.statementcurrencycodeiso <> lid.reportedcurrencycodeiso
AND fc.isflowitem = 0
AND p.periodlengthunitcode = 'W' ) THEN lid.lineiteminstancevalue
*
cds.dbo.Getaveragefxrate(lid.reportedcurrencycodeiso, lid.statementcurrencycodeiso,
Dateadd("WEEK", -p.periodlength, p.periodenddate), p.periodenddate)
ELSE lid.lineiteminstancevalue
END ) AS LineItemInstanceValue,
( CASE
WHEN ( lid.reportedcurrencycodeiso IS NOT NULL
AND fc.iscurrencydependent = 1
AND lid.statementcurrencycodeiso <> lid.reportedcurrencycodeiso
AND fc.isflowitem = 1 ) THEN
lid.adjustedforcorporateactionvalue *
cds.dbo.Exrate(lid.reportedcurrencycodeiso, lid.statementcurrencycodeiso, p.periodenddate)
WHEN ( lid.reportedcurrencycodeiso IS NOT NULL
AND fc.iscurrencydependent = 1
AND lid.statementcurrencycodeiso <> lid.reportedcurrencycodeiso
AND fc.isflowitem = 0
AND p.periodlengthunitcode = 'M' ) THEN
lid.adjustedforcorporateactionvalue
*
cds.dbo.Getaveragefxrate(lid.reportedcurrencycodeiso, lid.statementcurrencycodeiso,
Dateadd("MONTH", -p.periodlength, p.periodenddate), p.periodenddate)
WHEN ( lid.reportedcurrencycodeiso IS NOT NULL
AND fc.iscurrencydependent = 1
AND lid.statementcurrencycodeiso <> lid.reportedcurrencycodeiso
AND fc.isflowitem = 0
AND p.periodlengthunitcode = 'W' ) THEN
lid.adjustedforcorporateactionvalue
*
cds.dbo.Getaveragefxrate(lid.reportedcurrencycodeiso, lid.statementcurrencycodeiso,
Dateadd("WEEK", -p.periodlength, p.periodenddate), p.periodenddate)
ELSE lid.adjustedforcorporateactionvalue
END ) AS AdjustedForCorporateActionValue,
lid.reportedcurrencycodeiso,
lid.xbrlelementid,
xbrlele.xbrlelementname,
Cast(NULL AS CHAR(3)),
Cast(NULL AS DATETIME),
Cast(NULL AS DATETIME),
Cast(NULL AS CHAR(1)),
Cast(NULL AS DATETIME),
Cast(NULL AS SMALLINT),
src.dcn,
src.docformat,
lid.asreporteditemid,
ari.docbyteoffset,
ari.docbytelength,
ari.bookmark,
ari.itemdisplayednegativeflag,
ari.itemscalingfactor,
ari.itemdisplayedvalue,
ari.reportedvalue,
ari.reporteddescription,
ari.editeddescription,
src.documentid,
lid.isderived,
lid.statementsectioncode,
IsMissMatchPhysicalMeasureID =0,
lid.istotal,
lid.isexcludedfromstandardization,
si.isdetailed AS IsDetailedSection,
si.ispreliminary AS IsPreliminary,
IsCreditSection =Cast(NULL AS BIT),
IsCreditFCC =Cast(NULL AS BIT),
si.isproforma,
lll.instrumentndaid,
InterimTypeID = CASE p.periodicitycode
WHEN 'A' THEN 0
WHEN 'S' THEN 2
WHEN 'T' THEN 3
WHEN 'Q' THEN 4
END,
si.isnotcomparabletopriorperiod,
si.isfundbspecial,
si.isderived AS IsDerivedSI,
lid.systemderivedtypecode
--FBLog.tasktypeid,
--FBLog.systemstartdatetime,
--FBLog.issplit
FROM trf.dbo.lineiteminstance LID(nolock)
--INNER JOIN #fundbbackwardlog FBLog
-- ON FBLog.orgid = lid.orgid
-- AND FBLog.periodid = lid.periodid
-- AND FBLog.sourceid = lid.sourceid
-- AND FBLog.statementtypecode = lid.statementtypecode
-- AND FBLog.financialsbucketid = lid.financialsbucketid
-- AND FBLog.statementcurrencycodeiso =
-- lid.statementcurrencycodeiso
-- AND lid.asreporteditemid IS NOT NULL
-- AND lid.lineiteminstanceasreporteditemid IS NULL
INNER JOIN trf.dbo.statementinstance SI(nolock)
ON lid.orgid = si.orgid
AND lid.periodid = si.periodid
AND lid.sourceid = si.sourceid
AND lid.statementtypecode = si.statementtypecode
AND lid.financialsbucketid = si.financialsbucketid
AND lid.statementcurrencycodeiso = si.statementcurrencycodeiso
INNER JOIN trf.dbo.period P(nolock)
ON lid.orgid = p.orgid
AND lid.periodid = p.periodid
INNER JOIN trf.dbo.lineitem LLL(nolock)
ON lll.orgid = lid.orgid
AND lll.lineitemid = lid.lineitemid
INNER JOIN trf.dbo.financialconcept FC(nolock)
ON lll.financialconceptidglobal = fc.financialconceptid
LEFT OUTER JOIN trf.dbo.xbrlelement XBRLEle(nolock)
ON lid.xbrlelementid = xbrlele.xbrlelementid
INNER JOIN trf.dbo.asreportedinstance ARI(nolock)
ON lid.orgid = ari.orgid
AND lid.sourceid = ari.sourceid
AND lid.asreporteditemid = ari.asreporteditemid
INNER JOIN trf.dbo.[source] SRC(nolock)
ON src.orgid = ari.orgid
AND src.sourceid = ari.sourceid
WHERE ari.reportedvalue IS NOT NULL --AND SRC.DCN > '' --AND SRC.DocFormat > '' --AND ARI.BookMark > ''
Try to remove functions called in the query like : Exrate() and Getaveragefxrate().
Also change the case statement, where you are using subquery as following.
In the end of the query, use
left outer join trf.lineitemfundbdescription lifd
on lll.orgid = lifd.orgid and lll.lineitemid = lifd.lineitemid
and then the case will be changed to
case
when lifd.orgid is null then lll.lineitemname
else lifd.lineitemshortdescription End As LineItemName
It will fine tune your query to a level and gives you a correct execution plan and advice accordingly.
Remember that execution plan does not show the plan of user defined functions called with in the query.