How could I join these queries together? - sql

I have 2 queries. One includes a subquery and the other is a pretty basic query. I can't figure out how to combine them to return a table with name, workdate, minutes_inactive, and hoursworked.
I have the code below for what I have tried. The simple query is lines 1,2, and the last 5 lines. I also added a join clause (join punchclock p on p.servrepID = l.repid) to it.
Both these queries ran on their own so this is solely just the problem of combining them.
select
sr.sr_name as liaison, cast(date_created as date) workdate,
(count(date_created) * 4) as minutes_inactive,
(select
sr_name, cast(punchintime as date) as workdate,
round(sum(cast(datediff(minute,punchintime, punchouttime) as real) / 60), 2) as hoursworked,
count(*) as punches
from
(select
sr_name, punchintime = punchdatetime,
punchouttime = isnull((select top 1 pc2.punchdatetime
from punchclock pc2
where pc2.punchdatetime > pc.punchdatetime
and pc.servrepid = pc2.servrepid
and pc2.inout = 0
order by pc2.punchdatetime), getdate())
from
punchclock pc
join
servicereps sr on pc.servrepid = sr.servrepid
where
punchyear >= 2017 and pc.inout = 1
group by
sr_name, cast(punchintime as date)))
from
tbl_liga_popup_log l
join
servicereps sr on sr.servrepID = l.repid
join
punchclock p on p.servrepID = l.repid collate latin1_general_bin
group by
cast(l.date_created as date), sr.sr_name
I get this error:
Msg 102, Level 15, State 1, Line 19
Incorrect syntax near ')'
I keep getting this error but there are more errors if I adjust that part.

I don't know that we'll fix everything here, but there are a few issues with your query.
You have to alias your sub-query (technically a derived table, but whatever)
You have two froms in your outer query.
You have to join to the derived table.
Here's an crude example:
select
<some stuff>
from
(select col1 from table1) t1
inner join t2
on t1.col1 = t2.col2

The large error here is that you are placing queries in the select section (before the from). You can only do this if the query returns a single value. Else, you have to put your query in a parenthesis (you have done this) in the from section, give it an alias, and join it accordingly.
You also seem to be using group bys that are not needed anywhere. I can't see aggregation functions like sum().
My best bet is that you are looking for the following query:
select
sr_name as liaison
,cast(date_created as date) workdate
,count(distinct date_created) * 4 as minutes_inactive
,cast(punchintime as date) as workdate
,round(sum(cast(datediff(minute,punchintime,isnull(pc2_query.punchouttime,getdate())) as real) / 60), 2) as hoursworked
,count(*) as punches
from
punchclock pc
inner join servicereps sr on pc.servrepid = sr.servrepid
cross apply
(
select top 1 pc2.punchdatetime as punchouttime
from punchclock pc2
where pc2.punchdatetime > pc.punchdatetime
and pc.servrepid = pc2.servrepid
and pc2.inout = 0
order by pc2.punchdatetime
)q1
inner join tbl_liga_popup_log l on sr.servrepID = l.repid
where punchyear >= 2017 and pc.inout = 1

Related

How to force postgres to return 0 even if there are no rows matching query, using coalesce, group by and join

I've been trying hopelessly to get the following SQL statement to return the query results and default to 0 if there are no rows matching the query.
This is the intended result:
vol | year
-------+------
0 | 2018
Instead I get:
vol | year
-----+------
(0 rows)
Here is the sql statement:
select coalesce(vol,0) as vol, year
from (select sum(vol) as vol, year
from schema.fact_data
join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
join schema.product_data
on schema.fact_data.product_tag =
schema.product_data.tag
join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where "retailer"='MadeUpRetailer'
and "product_tag"='FakeProductTag'
and "year"='2018' group by year
) as DerivedTable;
I know the query works because it returns data when there is data. Just doesn't default to 0 as intended...
Any help in finding why this is the case would be much appreciated!
Using your subquery DerivedTable, you could write:
SELECT coalesce(DerivedTable.vol, 0) AS vol,
y.year
FROM (VALUES ('2018'::text)) AS y(year)
LEFT JOIN (SELECT ...) AS DerivedTable
ON DerivedTable.year = y.year;
Remove the GROUP BY (and the outer query):
select 2018 as year, coalesce(sum(vol), 0) as vol
from schema.fact_data f join
schema.period_data p
on f.period_tag = p.tag join
schema.product_data pr
on f.product_tag = pr.tag join
schema.market_data m
on fd.market_tag = m.tag
where "retailer" = 'MadeUpRetailer' and
"product_tag" = 'FakeProductTag' and
"year" = '2018';
An aggregation query with no GROUP BY always returns exactly one row, so this should do what you want.
EDIT:
The query would look something like this:
select v.yyyy as year, coalesce(sum(vol), 0) as vol
from (values (2018), (2019)) v(yyyy) left join
schema.fact_data f
on f.year = v.yyyy left join -- this is just an example. I have no idea where year is coming from
schema.period_data p
on f.period_tag = p.tag left join
schema.product_data pr
on f.product_tag = pr.tag left join
schema.market_data m
on fd.market_tag = m.tag
group by v.yyyy
However, you have to move the where conditions to the appropriate on clauses. I have no idea where the columns are coming from.
From the code you posted it is not clear in which table you have the year column.
You can use UNION to fetch just 1 row in case there are no rows in that table for the year 2018 like this:
select sum(vol) as vol, year
from schema.fact_data innrt join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
inner join schema.product_data
on schema.fact_data.product_tag = schema.product_data.tag
inner join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where
"retailer"='MadeUpRetailer' and
"product_tag"='FakeProductTag' and
"year"='2018'
group by "year"
union
select 0 as vol, '2018' as year
where not exists (
select 1 from tablename where "year" = '2018'
)
In case there are rows for the year 2018, then nothing will be fetched by the 2nd query,

Teradata SQL CASE Statement with multiple conditions

I have the below SQL query -
select distinct HospitalAcctID,
AdmitDate,
DischargeDate,
PatMRN,
Pat_id,
ICD,
MedCenter,
(case when SeqCount =1 and AdmitDate > '06/01/2013' and AdmitDate < '06/01/2018' then 1 else null end ) Firstdiag
from
(
select distinct acct.HSP_ACCOUNT_ID as HospitalAcctID,
cast(acct.ADM_DATE_TIME as date format 'mm/dd/yyyy') as AdmitDate,
cast(acct.DISCH_DATE_TIME as date format 'mm/dd/yyyy') as DischargeDate,
pat.pat_mrn_id as PatMRN,
pat.pat_id as Pat_id,
REF_BILL_CODE as ICD,
grp7.NAME AS MedCenter,
row_number() over (partition by PatMRN order by AdmitDate) as SeqCount
from acct
inner join pat on pat.pat_id = acct.pat_id
inner join hspenc on hspenc.CSN_ID = acct.CSN_ID
inner join dx on acct.ACCOUNT_ID = dx.ACCOUNT_ID and line = 1
inner join edg on dx.DX_ID = edg.DX_ID
inner join loc on loc.LOC_ID = acct.LOC_ID
inner join grp7 ON loc.RPT_GRP_SEVEN = grp7.RPT_GRP_SEVEN
where
grp7.NAME = 'SMC AREA'
and ADMIT_CONF_STAT_C in ('1','4')
and (edg. REF_BILL_CODE in ('431',
'431')
)
and ADT_PAT_CLASS_C in ('1204','12113')
order by AdmitDate;
)Admit
But I am getting the below syntax error -
Syntax error, expected something like an 'EXCEPT' keyword, 'UNION' Keyword or a 'MINUS' keyword between 'AdmitDate' and ','
In the outer select statement, I am trying to get the min (first ) date when the was first diagnosed. I also want to get only the patients who were diagnosed between 6/2013 to 6/2018 which is why I have the CASE statement. But the CASE statement is giving me error.
As #BarbarosĂ–zhan already wrote, remove the last line order by AdmitDate; in the Derived Table.
But there's no need for ROW_NUMBER:
select distinct acct.HSP_ACCOUNT_ID as HospitalAcctID,
cast(acct.ADM_DATE_TIME as date format 'mm/dd/yyyy') as AdmitDate,
cast(acct.DISCH_DATE_TIME as date format 'mm/dd/yyyy') as DischargeDate,
pat.pat_mrn_id as PatMRN,
pat.pat_id as Pat_id,
REF_BILL_CODE as ICD,
grp7.NAME AS MedCenter,
case when -- current rows is first row
min(AdmitDate)
over (partition by PatMRN) = AdminDate
-- current row within date range
and AdminDate >= DATE '2013-06-01' and AdmitDate < DATE '2018-06-01'
then 1
else null
end as Firstdiag
from acct
inner join pat on pat.pat_id = acct.pat_id
inner join hspenc on hspenc.CSN_ID = acct.CSN_ID
inner join dx on acct.ACCOUNT_ID = dx.ACCOUNT_ID and line = 1
inner join edg on dx.DX_ID = edg.DX_ID
inner join loc on loc.LOC_ID = acct.LOC_ID
inner join grp7 ON loc.RPT_GRP_SEVEN = grp7.RPT_GRP_SEVEN
where
grp7.NAME = 'SMC AREA'
and ADMIT_CONF_STAT_C in ('1','4')
and (edg. REF_BILL_CODE in ('431',
'431')
)
and ADT_PAT_CLASS_C in ('1204','12113')
order by AdmitDate;
I also switched to a Standard SQL date literal DATE '2013-06-01' instead of '06/01/2013'. There's only one possible format for the former (DATE 'YYYY-MM-DD') while the latter depends on the FORMAT of the base column and might fail when it changes (of course not in your query, because you defined it in the CAST).

Subquery returned more than 1 value.The subquery that contains SUM(dbo.SalarySettingsBreakup.Amount) AS AmountSSB

My sub-query returns more than one value and gives error.
(SELECT dbo.employee.id,
dbo.employee.employeecode,
dbo.employee.firstname,
dbo.employee.departmentid,
dbo.salarysettings.monthlyoffered,
dbo.salarysettings.id AS SalarySettingsID,
(SELECT Sum(amount) AS AmountVP
FROM voucherprocesses
WHERE vouchertypeid = 2
AND employee = dbo.employee.id
AND voucherdate BETWEEN '9/1/2017 12:00:00 AM' AND
'9/30/2017 12:00:00 AM'
GROUP BY employee) AS SalaryAdvance,
(SELECT Sum(dbo.salarysettingsbreakup.amount) AS AmountSSB
FROM dbo.employee
LEFT JOIN dbo.salarysettings
ON dbo.employee.id = dbo.salarysettings.employee
LEFT JOIN dbo.salarysettingsbreakup
ON dbo.salarysettings.id =
dbo.salarysettingsbreakup.salarysetting
WHERE dbo.salarysettingsbreakup.paymenttype = 2
AND dbo.salarysettingsbreakup.isactive = 1
GROUP BY dbo.employee.id) AS TotalDeduction,
(SELECT CASE
WHEN employee.joiningdate BETWEEN
'9/1/2017 12:00:00 AM' AND '9/30/2017 12:00:00 AM' THEN(
( salarysettings.monthlyoffered / 30 ) * ( 30 -
( Datepart(dd, joiningdate) - 1 ) ) )
ELSE 0
END) AS PayToBank
FROM dbo.employee
LEFT JOIN dbo.salarysettings
ON dbo.employee.id = dbo.salarysettings.employee
WHERE dbo.salarysettings.isactive = 1)
hope will work, try this :
(SELECT e.id,
e.employeecode,
e.firstname,
e.departmentid,
dbo.salarysettings.monthlyoffered,
dbo.salarysettings.id AS SalarySettingsID,
(SELECT Sum(amount) AS AmountVP
FROM voucherprocesses
WHERE vouchertypeid = 2
AND voucherprocesses.employee = e.id
AND voucherdate BETWEEN '9/1/2017 12:00:00 AM' AND
'9/30/2017 12:00:00 AM'
) AS SalaryAdvance,
(SELECT Sum(dbo.salarysettingsbreakup.amount) AS AmountSSB
FROM dbo.employee e2
LEFT JOIN dbo.salarysettings
ON e2.id = dbo.salarysettings.employee
LEFT JOIN dbo.salarysettingsbreakup
ON dbo.salarysettings.id =
dbo.salarysettingsbreakup.salarysetting
AND dbo.salarysettingsbreakup.paymenttype = 2
AND dbo.salarysettingsbreakup.isactive = 1
WHERE e2.id = e.id
) AS TotalDeduction,
(SELECT CASE
WHEN employee.joiningdate BETWEEN
'9/1/2017 12:00:00 AM' AND '9/30/2017 12:00:00 AM' THEN(
( salarysettings.monthlyoffered / 30 ) * ( 30 -
( Datepart(dd, joiningdate) - 1 ) ) )
ELSE 0
END) AS PayToBank
FROM dbo.employee e
LEFT JOIN dbo.salarysettings
ON e.id = dbo.salarysettings.employee
WHERE dbo.salarysettings.isactive = 1)
You have much to learn. You need to understand how subqueries work as well as outer joins. The following is wrong due to 2 issues.
(SELECT Sum(dbo.salarysettingsbreakup.amount) AS AmountSSB
FROM dbo.employee
LEFT JOIN dbo.salarysettings
ON dbo.employee.id = dbo.salarysettings.employee
LEFT JOIN dbo.salarysettingsbreakup
ON dbo.salarysettings.id =
dbo.salarysettingsbreakup.salarysetting
WHERE dbo.salarysettingsbreakup.paymenttype = 2
AND dbo.salarysettingsbreakup.isactive = 1
GROUP BY dbo.employee.id) AS TotalDeduction,
First is that you did not properly correlate the subquery. As Rahmat posted (but did not explain), you need to associate the employee ID from the outer query with the subquery. Because you did not correlate the subquery, it produces multiple rows for each row in the outer query - producing your error.
In addition, your lack of understanding about the correlation causes you to add complexity and a logical mistake (which gets covered up when correlated correctly). There is no need to include the employee table in your subquery. Since you correlate it to the employee table in the main query, it is redundant. In addition, you don't need to group by anything in the subquery since it is intended to generate a single scalar value per row in the outer query. And lastly, there is no purpose to outer joining in the subquery. Either you have matching rows in salarysettingsbreakup or you don't. An inner and outer join will achieve the same result - NULL if no matches. I also question whether you need to sum at all given the table and column names involved. You should search for explanations about how outer joins work and what happens when you reference columns from the unpreserved table (e.g. salarysettingsbreakup) in the where clause.
So a better subquery is:
(SELECT Sum(bkp.amount)
FROM dbo.salarysettings as sset
INNER JOIN dbo.salarysettingsbreakup as bkp
ON sset.id = bkp.salarysetting
AND bkp.paymenttype = 2
AND bkp.isactive = 1
WHERE sset.employee = dbo.employee.id) as TotalDeduction,
Note the inclusion of some best practices. Give a readable alias to your tables and use it with all of the columns referenced. I also despise the practice of using a table name as a column name - that adds to the confusion of reading your queries IMO.

Only month end values for each identifier

For the code below I am attempting to select only the month end values for all unique FundId's. The code below keeps giving me the error of
Msg 164, Level 15, State 1, Line 16
Each GROUP BY expression must contain at least one column that is not an outer reference.
How can I fix the where statement to pull all month end values for each fundid
SELECT TOP 10000 a.[PerformanceId]
,[InvestmentType]
,[EndDate]
,a.[CurrencyId]
,[AssetValue]
,c.FundId
FROM [StatusData_DMWkspaceDB].[dbo].[NetAssetsValidationFailure] a
LEFT JOIN MappingData_GAPortDB.dbo.PerformanceLevelMapping b
ON a.PerformanceId = b.PerformanceId
LEFT JOIN MappingData_GAPortDB.dbo.FundClassMatching c
ON b.SecId = c.SecId
WHERE a.EndDate IN (
SELECT MAX(a.EndDate)
From [StatusData_DMWkspaceDB].[dbo].[NetAssetsValidationFailure]
GROUP BY c.FundId, Month(a.EndDate), YEAR(a.EndDate))
This is your query:
SELECT TOP 10000 navf.[PerformanceId], [InvestmentType], [EndDate],
navf.[CurrencyId], [AssetValue], fcm.FundId
FROM [StatusData_DMWkspaceDB].[dbo].[NetAssetsValidationFailure] navf LEFT JOIN
MappingData_GAPortDB.dbo.PerformanceLevelMapping plm
ON navf.PerformanceId = plm.PerformanceId LEFT JOIN
MappingData_GAPortDB.dbo.FundClassMatching fcm
ON l.m.SecId = fcm.SecId
WHERE navf.EndDate IN (SELECT MAX(navf.EndDate)
From [StatusData_DMWkspaceDB].[dbo].[NetAssetsValidationFailure] navf
GROUP BY fcm.FundId, Month(navf.EndDate), YEAR(navf.EndDate)
);
Learn to use sensible table aliases, so the query is easier to write and to read.
In any case, your WHERE clause is only referencing outer tables in the GROUP BY. The message is quite clear.
I'm not even sure what you want to do, but I am guessing that this is a working version of what you want:
SELECT x.*
FROM (SELECT navf.[PerformanceId], [InvestmentType], [EndDate],
navf.[CurrencyId], [AssetValue], fcm.FundId,
ROW_NUMBER() OVER (PARTITION BY fcm.FundId, Month(navf.EndDate), YEAR(navf.EndDate)
ORDER BY navf.EndDate DESC
) as seqnum
FROM [StatusData_DMWkspaceDB].[dbo].[NetAssetsValidationFailure] navf LEFT JOIN
MappingData_GAPortDB.dbo.PerformanceLevelMapping plm
ON navf.PerformanceId = plm.PerformanceId LEFT JOIN
MappingData_GAPortDB.dbo.FundClassMatching fcm
ON l.m.SecId = fcm.SecId
) x
WHERE seqnum = 1;

SQL - Derived tables issue

I have the following SQL query:
SELECT VehicleRegistrations.ID, VehicleRegistrations.VehicleReg,
VehicleRegistrations.Phone, VehicleType.VehicleTypeDescription,
dt.ID AS 'CostID', dt.IVehHire, dt.FixedCostPerYear, dt.VehicleParts,
dt.MaintenancePerMile, dt.DateEffective
FROM VehicleRegistrations
INNER JOIN VehicleType ON VehicleRegistrations.VehicleType = VehicleType.ID
LEFT OUTER JOIN (SELECT TOP (1) ID, VehicleRegID, DateEffective, IVehHire,
FixedCostPerYear, VehicleParts, MaintenancePerMile
FROM VehicleFixedCosts
WHERE (DateEffective <= GETDATE())
ORDER BY DateEffective DESC) AS dt
ON dt.VehicleRegID = VehicleRegistrations.ID
What I basically want to do is always select the top 1 record from the 'VehicleFixedCosts' table, where the VehicleRegID matches the one in the main query. What is happening here is that it's selecting the top row before the join, so if the vehicle registration of the top row doesn't match the one we're joining to it returns nothing.
Any ideas? I really don't want to have use subselects for each of the columns I need to return
Try this:
SELECT vr.ID, vr.VehicleReg,
vr.Phone, VehicleType.VehicleTypeDescription,
dt.ID AS 'CostID', dt.IVehHire, dt.FixedCostPerYear, dt.VehicleParts,
dt.MaintenancePerMile, dt.DateEffective
FROM VehicleRegistrations vr
INNER JOIN VehicleType ON vr.VehicleType = VehicleType.ID
LEFT OUTER JOIN (
SELECT ID, VehicleRegID, DateEffective, IVehHire, FixedCostPerYear, VehicleParts, MaintenancePerMile
FROM VehicleFixedCosts vfc
JOIN (
select VehicleRegID, max(DateEffective) as DateEffective
from VehicleFixedCosts
where DateEffective <= getdate()
group by VehicleRegID
) t ON vfc.VehicleRegID = t.VehicleRegID and vfc.DateEffective = t.DateEffective
) AS dt
ON dt.VehicleRegID = vr.ID
Subquery underneath dt might need some grouping but without schema (and maybe sample data) it's hard to say which column should be involved in that.