Related
I am needing help converting a PostgreSQL query to MSSQ.
Below is what i have done so far but i am issuing with the function and array areas which i do not think are allowed in MS SQL.
Is there something that that i need to do change the function and looks the WHERE statement has an array in it too.
I have added the select statement for the #temp table but when i create the #temp table i am getting errors saying incorrect syntax
CREATE FUNCTION pm_aggregate_report
(
_facility_ids uuid[]
, _risk_ids uuid[] DEFAULT NULL::uuid[]
, _assignee_ids uuid[] DEFAULT NULL::uuid[]
, _start_date date DEFAULT NULL::date
, _end_date date DEFAULT NULL::date
)
RETURNS TABLE
(
facility character varying
, pm_id uuid, grouped_pm boolean
, risk_id uuid
, risk character varying
, pm_status_id uuid
, user_id uuid
, assignee text
, completed_by uuid
, total_labor bigint
)
CREATE TABLE #tmp_pm_aggregate
(
facility_id VARCHAR(126),
pm_id VARCHAR(126),
grouped_pm VARCHAR(126),
risk_id VARCHAR(126),
pm_status_id VARCHAR(126),
user_id VARCHAR(126),
completed_by VARCHAR(126)
)
SELECT DISTINCT
COALESCE(gp.facility_id, a.facility_id) as facility_id,
COALESCE(p.grouped_pm_id, p.id) as pm_id,
CASE WHEN p.grouped_pm_id IS NULL THEN false ELSE true END as grouped_pm,
COALESCE(gp.risk_id, a.risk_id) as risk_id,
COALESCE(gp.pm_status_id, p.pm_status_id) as pm_status_id,
COALESCE(gass.user_id, sass.user_id) as user_id,
COALESCE(gp.completed_by, p.completed_by) as completed_by
FROM pms p
JOIN assets a
ON p.asset_id = a.id
LEFT JOIN grouped_pms gp
ON p.grouped_pm_id = gp.id
LEFT JOIN assignees sass
ON p.id = sass.record_id
AND sass.type = 'single_pm'
LEFT JOIN assignees gass
ON p.grouped_pm_id = gass.record_id
AND gass.type = 'grouped_pm'
LEFT JOIN users u
ON (sass.user_id = u.id OR gass.user_id = u.id)
WHERE a.facility_id = ANY(_facility_ids)
AND NOT a.is_component
AND COALESCE(gp.pm_status_id, p.pm_status_id) in ('f9bdfc17-3bb5-4ec0-8477-24ef05ea3b9b', '06fc910c-3d07-4284-8f6e-8fb3873f5333')
AND COALESCE(gp.completion_date, p.completion_date) BETWEEN COALESCE(_start_date, '1/1/2000') AND COALESCE(_end_date, '1/1/3000')
AND COALESCE(gp.show_date, p.show_date) <= CURRENT_TIMESTAMP
AND COALESCE(gass.user_id, sass.user_id) IS NOT NULL
AND u.user_type_id != 'ec823d98-7023-4908-8006-2e33ddf2c11b'
AND (_risk_ids IS NULL OR COALESCE(gp.risk_id, a.risk_id) = ANY(_risk_ids)
AND (_assignee_ids IS NULL OR COALESCE(gass.user_id, sass.user_id) = ANY(_assignee_ids);
SELECT
f.name as facility,
t.pm_id,
t.grouped_pm,
t.risk_id,
r.name as risk,
t.pm_status_id,
t.user_id,
u.name_last + ', ' + u.name_first as assignee,
t.completed_by,
ISNULL(gwl.total_labor, swl.total_labor) as total_labor
FROM #tmp_pm_aggregate t
JOIN facilities f
ON t.facility_id = f.id
JOIN risks r
ON t.risk_id = r.id
JOIN users u
ON t.user_id = u.id
LEFT JOIN (SELECT wl.record_id, wl.user_id, SUM(wl.labor_time) as total_labor
FROM work_logs wl
WHERE wl.type = 'single_pm'
GROUP BY wl.record_id, wl.user_id) as swl
ON t.pm_id = swl.record_id
AND t.user_id = swl.user_id
AND t.grouped_pm = false
LEFT JOIN (SELECT wl.record_id, wl.user_id, SUM(wl.labor_time) as total_labor
FROM work_logs wl
WHERE wl.type = 'grouped_pm'
GROUP BY wl.record_id, wl.user_id) as gwl
ON t.pm_id = gwl.record_id
AND t.user_id = gwl.user_id
AND t.grouped_pm = true
ORDER BY facility,
assignee,
risk;
DROP TABLE #tmp_pm_aggregate;
You can create an inline Table Valued Function, and simply return a resultset from it. You do not need (and cannot use) a temp table, you do not declare the returned "rowset" shape.
For the array parameters, you can use a Table Type:
CREATE TYPE dbo.GuidList (value uniqueidentifier NOT NULL PRIMARY KEY);
Because the table parameters are actual tables, you must query them like this (NOT EXISTS (SELECT 1 FROM #risk_ids) OR ISNULL(gp.risk_id, a.risk_id) IN (SELECT r.value FROM #risk_ids))
The parameters must start with #
There is no boolean type, you must use bit
Always use deterministic date formats for literals. yyyymmdd works for dates. Do you need to take into account hours and minutes, because you haven't?
ISNULL generally performs better than COALESCE in SQL Server, as the compiler understands it better
You may want to pass a separate parameter showing whether you passed in anything for the optional table parameters
I suggest you look carefully at the actual query: why does it need DISTINCT? It performs poorly, and is usually a code-smell indicating poorly thought-out joins. Perhaps you need to combine the two joins on assignees, or perhaps you should use a row-numbering strategy somewhere.
CREATE FUNCTION dbo.pm_aggregate_report
(
#facility_ids dbo.GuidList
, #risk_ids dbo.GuidList
, #assignee_ids dbo.GuidList
, #start_date date
, #end_date date
)
RETURNS TABLE AS RETURN
SELECT DISTINCT -- why DISTINCT, perhaps rethink your joins
ISNULL(gp.facility_id, a.facility_id) as facility_id,
ISNULL(p.grouped_pm_id, p.id) as pm_id,
CASE WHEN p.grouped_pm_id IS NULL THEN CAST(0 AS bit) ELSE CAST(1 AS bit) END as grouped_pm,
ISNULL(gp.risk_id, a.risk_id) as risk_id,
ISNULL(gp.pm_status_id, p.pm_status_id) as pm_status_id,
ISNULL(gass.user_id, sass.user_id) as user_id,
ISNULL(gp.completed_by, p.completed_by) as completed_by
FROM pms p
JOIN assets a
ON p.asset_id = a.id
LEFT JOIN grouped_pms gp
ON p.grouped_pm_id = gp.id
LEFT JOIN assignees sass
ON p.id = sass.record_id
AND sass.type = 'single_pm'
LEFT JOIN assignees gass
ON p.grouped_pm_id = gass.record_id
AND gass.type = 'grouped_pm'
LEFT JOIN users u
ON (sass.user_id = u.id OR gass.user_id = u.id) -- is this doubling up your rows?
WHERE a.facility_id IN (SELECT f.value FROM #facility_ids f)
AND a.is_component = 0
AND ISNULL(gp.pm_status_id, p.pm_status_id) in ('f9bdfc17-3bb5-4ec0-8477-24ef05ea3b9b', '06fc910c-3d07-4284-8f6e-8fb3873f5333')
AND ISNULL(gp.completion_date, p.completion_date) BETWEEN ISNULL(#start_date, '20000101') AND ISNULL(#end_date, '30000101') -- perhaps use >= AND <
AND ISNULL(gp.show_date, p.show_date) <= CURRENT_TIMESTAMP
AND ISNULL(gass.user_id, sass.user_id) IS NOT NULL
AND u.user_type_id != 'ec823d98-7023-4908-8006-2e33ddf2c11b'
AND (NOT EXISTS (SELECT 1 FROM #risk_ids) OR ISNULL(gp.risk_id, a.risk_id) IN (SELECT r.value FROM #risk_ids))
AND (NOT EXISTS (SELECT 1 FROM #assignee_ids) OR ISNULL(gass.user_id, sass.user_id) IN (SELECT aid.value FROM #assignee_ids aid));
I need to create concatenated query will get data with checking data in other tables.
Firstly I declared (and filled it) two tables with list of ID I'll check in other tables. On next step (2) I declared new table and filled it values I get by some checking params. This table contains only one column (ID).
After filling if I execute SELECT DISTINCT query from this table I'll get really unique ID. It's OK.
But on next step (3) I declare more one table and filling it by 3 tables. Of course it contains many duplicates. But I must create this query for checking and concatenating. And after that if I execute select distinct h from #NonUnicalConcat it returns many duplicate IDs.
What I did wrong? Where is an error?
USE CurrentBase;
--STEP 1
DECLARE #TempCSTable TABLE(TempTableIDColumn int);
INSERT INTO #TempCSTable VALUES('3'),('4');
DECLARE #TempCVTable TABLE(TempTableIDColumn int);
INSERT INTO #TempCVTable VALUES('2'),('13');
--STEP 2
DECLARE #TempIdTable TABLE(id int);
INSERT INTO #TempIdTable
SELECT TT1.ID
FROM Table1 AS TT1
LEFT OUTER JOIN Table2 ON Table2.ID = TT1.OptionalColumn
LEFT OUTER JOIN Table3 AS TT2 ON TT2.ID = TT1.OptionalColumn
LEFT OUTER JOIN Table4 AS TT3 ON TT3.ID = TT2.OptionalColumn
WHERE TT1.ValueDate > '2020-06-30'
AND TT1.ValueDate < '2020-08-04'
AND TT1.OptBool = '1'
AND TT1.OptBool2 = '0'
AND EXISTS
(
SELECT Table5.ID
FROM Table5
WHERE Table5.ID = TT1.ID
AND Table5.CV IN
(
SELECT TempTableIDColumn
FROM #TempCVTable
)
AND Table5.OptBool = '1'
)
AND EXISTS
(
SELECT Table6.ID
FROM Table6
WHERE Table6.IID = TT3.ID
AND Table6.CS IN
(
SELECT TempTableIDColumn
FROM #TempCSTable
)
);
SELECT distinct * FROM #TempIdTable;--this code realy select distinct
--STEP 3
DECLARE #NonUnicalConcat TABLE(c int, s int, h int);
INSERT INTO #NonUnicalConcat
SELECT TT1.TempTableIDColumn AS cc,
TT2.TempTableIDColumn AS ss,
TT3.id AS hh
FROM #TempCVTable AS TT1,
#TempCSTable AS TT2,
#TempIdTable AS TT3
WHERE NOT EXISTS
(
SELECT HID
FROM OtherBase.dbo.Table1
WHERE HID = TT3.id
AND CS = TT2.TempTableIDColumn
AND CV = TT1.TempTableIDColumn
);
select distinct h from #NonUnicalConcat;--this code return many duplicates
I have added table function in the where clause.
select cmp_id, acno_code, sl_type, sl_code, 0 op_Dr, 0 op_cr, 0 tr_Dr, sum(amount) tr_Cr
from vf_finance
where cmp_id =#cmp_id1
and unitcode in (select * from UTILfn_Split( #unit_code,',') )
and stat_code in ('AT','PR' )
--and pc_code in (select * from UTILfn_Split( #sba,',') )
AND DOC_dT >=convert(datetime,#from_date,103) and doc_Dt <= convert(datetime,#to_date,103)
and amount < 0
GROUP BY cmp_id, acno_code, sl_type, sl_code
) as gl
inner join ps_Accmas acc on acc.cmp_id = gl.cmp_id and acc.acno_Code = gl.acno_code
inner join ps_owner o on gl.cmp_id = o.cmp_id
left outer join view_sl_code sl on gl.cmp_id = sl.cmp_id and gl.sl_type = sl.sl_type and gl.sl_Code = sl.sl_Code
inner join ps_slType slt on gl.cmp_id = slt.cmp_id and gl.sl_Type = slt.sl_type
where sl.sl_type in (select * from UTILfn_Split( #sl_type,',') )
and acc.acno_code in(select * from UTILfn_Split( #facno_code,',') )
group by gl.cmp_id, gl.acno_code,gl.sl_code,gl.sl_type,slt.sl_DEsc,acc.acno_DEsc, sl.sl_DEsc, o.owner_name
order by gl.cmp_id, gl.acno_code,gl.sl_code,gl.sl_type
Can anyone please suggest how I can avoid function in where clause?
You may try this. There are some issues in this existing query which I'll point first
First unitcode in (select * from UTILfn_Split( #unit_code,',') here you must use one column name instead of *, although i don't know about your function UTILfn_Split but still mention column name is preferable.
for your query you may use inner join instead of in with function having return type table.
Instead of
sl.sl_type in (select * from UTILfn_Split( #sl_type,',') )
You may try this
yourtble as sl inner join
(select value from UTILfn_Split( #sl_type,',') as t2
on sl.sl_type = t2.[value] ---- here column name with t2 depends on your function,
---what table structure is returning, in your case it is [value]
Im getting a conversion error when using the rownumber function on sql-server. I know plenty of similar threads have been posted but ive looked at them and they have different issues.
Conversion failed when converting the varchar value 'RN' to data type int.
It doesnt tell me where the problem is occuring. Does anyone have an idea of where it could be going wrong apart from the rownumber function?
This CTE is getting a previous transaction
, PRETRANSACTIONS AS (
SELECT DISTINCT
CONT.POH_ID AS POH_ID
,CONT.POH_POLICYNUMBER AS Contract_Number
,row_number() over (
partition by CONT.POH_ID
order by TRANS.txh_effectivedate desc
) AS 'RN'
,TXN_STAT.Txs_DESCRIPTION_I AS Transaction_Status_2
,TRANS.txh_effectivedate AS Transaction_Date_2
,TXN_DES.Txt_DESCRIPTION_I AS Transaction_Type_2
,TRX_RES.TRE_AMTPROCESSED AS Transaction_Amount_2
From Se2FAST.dbo.Cm_Opt_Poh_PolicyHdr_S CONT
JOIN BASE BASE
ON BASE.Poh_ID = CONT.POH_ID
INNER JOIN Se2FAST.dbo.Cm_Opt_Pch_PolicyCovHdr_S policyCov
ON CONT.Poh_ID = policyCov.Pch_POLICYHDRID
AND policycov.pch_sequence = 1
INNER JOIN [dbo].[Cm_Sys_Pst_PolicyStatus_I] PST
ON PST.Pst_ID_I = CONT.Poh_Status
LEFT JOIN se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRANS
ON TRANS.TXH_POLICYHDRID = CONT.POH_ID
AND TRANS.txh_effectivedate < ( SELECT TOP 1 TRAN1.txh_effectivedate
FROM se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRAN1
WHERE TRAN1.TXH_POLICYHDRID = CONT.POH_ID
ORDER BY txh_effectivedate DESC)
LEFT JOIN se2Fast.dbo.Cm_Opt_Tre_TrxRes_S AS TRX_RES
ON TRANS.Txh_ID = TRX_RES.Tre_TRXHDRID
LEFT JOIN se2Fast.dbo.Cm_Sys_Txt_TrxType_I TXN_DES
ON TRANS.Txh_TRXTYPEID = TXN_DES.Txt_ID_I
--AND TXN_DES.Txt_DESCRIPTION_I NOT IN (
--'Anniversary','Monthiversary','Quarterversary','Calendar Year End')
--AND TXN_DES.Txt_DESCRIPTION_I IS NOT NULL
LEFT JOIN se2Fast.dbo.Cm_Sys_Txs_TrxStatus_I TXN_STAT
ON Trans.Txh_TRXSTATUS = TXN_STAT.Txs_ID_I
AND TXN_STAT.Txs_DESCRIPTION_I = 'Completed'
WHERE 'RN' = 2
)
WHERE 'RN' = 2 is comparing two values, the string 'RN' and the integer 2. When SQL Server parses the expression, it is attempting to convert the literal value 'RN' to a numeric value to perform the integer comparison. Obviously, RN cannot be converted to a numeric value so you are getting an error.
In SQL Server, aliases are materialized after the WHERE/GROUP/HAVING clauses, but before the ORDER BY clause. This means you can't use the alias within the filter of the query it was assigned. You need to generate your column alias in a subquery before you can use it in a comparison.
It looks like you've mixed up your query. You've started as CTE named 'PRETRANSACTIONS', but then you've tried to alias it as a column after the closing parenthesis, AS 'RN'. A CTE must be referenced in the FROM before you can use the columns in the SELECT. If this is just a column expression, get rid of 'PRETRANSACTIONS AS' at the beginning.
WITH PRETRANSACTIONS AS (
SELECT DISTINCT
CONT.POH_ID AS POH_ID
,CONT.POH_POLICYNUMBER AS Contract_Number
,row_number() over (
partition by CONT.POH_ID
order by TRANS.txh_effectivedate desc)
AS RN)
SELECT RN,
TXN_STAT.Txs_DESCRIPTION_I AS Transaction_Status_2
,TRANS.txh_effectivedate AS Transaction_Date_2
,TXN_DES.Txt_DESCRIPTION_I AS Transaction_Type_2
,TRX_RES.TRE_AMTPROCESSED AS Transaction_Amount_2
From Se2FAST.dbo.Cm_Opt_Poh_PolicyHdr_S CONT
JOIN BASE BASE
ON BASE.Poh_ID = CONT.POH_ID
JOIN PRETRANSACTIONS
ON BASE.POH_ID = PRETRANSACTIONS.POH_ID
INNER JOIN Se2FAST.dbo.Cm_Opt_Pch_PolicyCovHdr_S policyCov
ON CONT.Poh_ID = policyCov.Pch_POLICYHDRID
AND policycov.pch_sequence = 1
INNER JOIN [dbo].[Cm_Sys_Pst_PolicyStatus_I] PST
ON PST.Pst_ID_I = CONT.Poh_Status
LEFT JOIN se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRANS
ON TRANS.TXH_POLICYHDRID = CONT.POH_ID
AND TRANS.txh_effectivedate < ( SELECT TOP 1 TRAN1.txh_effectivedate
FROM se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRAN1
WHERE TRAN1.TXH_POLICYHDRID = CONT.POH_ID
ORDER BY txh_effectivedate DESC)
LEFT JOIN se2Fast.dbo.Cm_Opt_Tre_TrxRes_S AS TRX_RES
ON TRANS.Txh_ID = TRX_RES.Tre_TRXHDRID
LEFT JOIN se2Fast.dbo.Cm_Sys_Txt_TrxType_I TXN_DES
ON TRANS.Txh_TRXTYPEID = TXN_DES.Txt_ID_I
--AND TXN_DES.Txt_DESCRIPTION_I NOT IN (
--'Anniversary','Monthiversary','Quarterversary','Calendar Year End')
--AND TXN_DES.Txt_DESCRIPTION_I IS NOT NULL
LEFT JOIN se2Fast.dbo.Cm_Sys_Txs_TrxStatus_I TXN_STAT
ON Trans.Txh_TRXSTATUS = TXN_STAT.Txs_ID_I
AND TXN_STAT.Txs_DESCRIPTION_I = 'Completed'
WHERE PRETRANSACTIONS.RN = 2
On a separate note, never use DISTINCT in the same set as ROW_NUMBER. ROW_NUMBER generates a unique number for every row, therefore every row is distinct. All that will do is add sorting overhead without eliminating any rows. You can use RANK or DENSE_RANK instead.
dont use 'RN', just RN without quotes.
You are getting this error because you are comparing the Text value 'RN' with an Integer value 2 in the where clause. But since 'RN' is a column and you want to return all the files that have a value 2 in the field 'RN' instead of
WHERE **'RN'** = 2
just type
WHERE RN = 2
RN without quotes as it is the name of the column.
I have three tables:
1: Station_Details (master data table)
2: RF_Details
3: WL_Details
As mention in below image.
I need a to take data from all three table in to a output table
Master data from Station_details and other data from RF and WL tables.
If RF_Details and WL_Details tables are having same station id and same DateTime then in output table both rows details will show in one row.
If DateTime are different then it will appear in different rows.
I tried this sql query but I am not getting the same output like OUTPUT Table.
select rf.StationID, st.stationname, st.state,rf.rf,rf.cum-rf,wl.wl,DataTime
from [RF_Details] rf
join [WL_Details] wl
join Station_Details st
on rf.StationID = wl.StationId and
rf.DataRecieved=wl.DataRecieved and
st.stationid =rf.stationid and
st.stationid = wl.stationid;
But it didn't give the right number of rows and output.
Please help me for the same.
You should always put the join conditions along with the join itself. Also, adding the INNER is a practice I follow to ensure no extra records are returned.
SELECT rf.StationID, st.stationname, st.state, wl.DataRecieved, wl.waterlevel1,
rf.dailyrainfall, rf.cumrainfall
FROM [RF_Details] rf
INNER JOIN [WL_Details] wl
ON rf.StationID = wl.StationId AND
rf.DataRecieved=wl.DataRecieved
INNER JOIN Station_Details st
ON st.stationid =rf.stationid AND
st.stationid = wl.stationid;
declare #station_details table(id int, station_id varchar(10),station_name varchar(10),state varchar(10))
declare #rf_details table (id int, station_id varchar(10),rf int, cum_rf int, dt dateTIME)
declare #wl_details table (id int, station_id varchar(10),wl int,dt datetime)
insert into #station_details values
(1,'DEL-NDL','NDL','DEL'),
(2,'UP-LKO','LKO','UP'),
(3,'MP-BHP','BHP','MP'),
(4,'MHR-MUM','MUM','MHR')
INSERT INTO #RF_DETAILS VALUES
(1,'DEL-NDL',42,435,'2016-06-13 05:15:00'),
(2,'UP-LKO',0,501,'2016-06-13 05:15:00'),
(3,'MP-BHP',20,350,'2016-06-13 05:15:00'),
(4,'MHR-MUM',30,200,'2016-06-13 05:15:00'),
(5,'MHR-MUM',15,100,'2016-06-14 05:15:00'),
(6,'UP-LKO',50,350,'2016-06-13 05:15:00')
INSERT INTO #WL_DETAILS VALUES
(1,'DEL-NDL',25,'2016-06-13 05:15:00'),
(2,'UP-LKO',35,'2016-06-13 05:30:00'),
(3,'MP-BHP',46,'2016-06-13 05:45:00'),
(4,'MHR-MUM',20,'2016-06-13 05:15:00'),
(5,'MHR-MUM',15,'2016-06-14 05:15:00'),
(6,'UP-LKO',60,'2016-06-13 05:15:00')
;with cte as
(
SELECT case
when rf.dt = wl.dt then 'Y'
else 'N'
end as matched,
rf.id as id,rf.station_id as stationid,rf.rf as rf , rf.cum_rf as cumrf , rf.dt as rfdt,
wl.id as wlid, wl.station_id ,wl.wl ,wl.dt as wldte,
rf.station_id as station,rf.dt as rfdte
FROM #RF_DETAILS RF
JOIN #WL_DETAILS WL ON rf.id = wl.id and RF.STATION_ID = WL.STATION_ID
)
select row_number() over (order by s.id) newid,
s.id,s.station_id,sd.station_name,sd.state,s.rf,s.cumrf,s.wl,
case
when s.srce = 'L' then s.rfdte
else s.wldte
end as 'Date'
from
(
select 'L' as srce,cte.id,cte.station_id,cte.rf,cte.cumrf, cte.wl as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'Y'
union
select 'L' as srce,cte.id,cte.station_id,cte.rf,cte.cumrf, null as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'N'
union all
select 'R' as srce,cte.id * 10,cte.station_id,null,null, cte.wl as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'N'
) s
join #station_details sd on sd.station_id = s.station_id
order by s.id
You should redesign your database: right now you have a secondary key in RF_Details and WL_Details - DateTime. Which plays a role of a foreign key between them. Which is no good and will continue confusing you every time you need to join those table or collect corresponding data.
There should be another table like Station_Records which will store a row per every record for that station: (id, station_id, record_date_time). RF and WL rows if any should refer this table instead of referring Station_Details with station_id and one another with datetime.
With current structure you need to do full join of RF and WL to get both: matching by datetime - in same row, not matching - in separate rows.
select sd.station_name, Station_Records.*
from Station_Details sd
inner join
(
select
IsNull(rf.station_id, wl.station_id) station_id,
IsNull(rf.DataRecieved, wl.DataRecieved) DataRecieved,
rf.rf, rf.cum-rf, wl.wl
from [RF_Details] rf
full join [WL_Details] wl
on wl.station_id = rf.station_id
and wl.DataRecieved = rf.DataRecieved
) Station_Records
on Station_Records.station_ud = sd.station_id
concrete implementation may consist of OUTER APPLY or even be without any subqueries - it does not really matter currently.
Modify your table structure and you will always know all matching records:
select
sd.station_id, sd.station_name,
sr.DataRecieved
rf.rf, rf.cum-rf,
wl.wl
from Station_Details sd
inner join Station_Records sr
on sr.station_id = sd.station_id
left join RF_Details rf
on rf.record_id = sr.record_id
left join WL_Details wl
on wl.record_id = sr.record_id