Creating INNER Joins with IIF - sql

I am trying to join three tables using and inner join and have the contents of one change colour if an e-mail has been sent.
Below is my query
SELECT IIF(COUNT Holdsent.job)>0, #STD, #RED) AS Colour, jobs.job, jobs.jobstatus, jobs.client, jobs.logdate
FROM jobs INNER JOIN clients ON clients.client = jobs.client INNER JOIN holdsent ON holdsent.job = jobs.job
WHERE (jobs.jobstatus = 'HOLD' OR jobs.jobstatus = 'CLIHOLD')
Below is the error I receive
Expected lexical element not found: (missing ( in aggregate function
[Parsing Expression (column1 in the SELECT clause)] -- Location of
error in the SQL statement is:1 SELECT IIF(COUNT
Holdsent.job)>0,#STD, #RED) AS COLOUR,jobs.job,
jobs.jobstatus,jobs.client,jobs.logdate FROM jobs INNER JOIN clients
ON clients.client = jobs.client INNER JOIN holdsent ON holdsent.job =
jobs.job WHERE (jobs.jobstatus = 'HOLD' OR jobs.jobstatus =
'CLIHOLD')
I am new to SQL and can do basic queries, but am not clear on IIF. Thank you in advance for any help you can provide.

iif is a special function from MS Access, which SQL Server has started supporting with the most recent version. The correct SQL form is the case statement. An improved version of your query, written in standard SQL, is:
SELECT (case when COUNT(hs.job)>0 then #STD else #RED end) AS Colour,
j.job, j.jobstatus, j.client, j.logdate
FROM jobs j INNER JOIN
clients c
ON c.client = j.client INNER JOIN
holdsent hs
ON hs.job = j.job
WHERE j.jobstatus in ('HOLD', 'CLIHOLD')

Sorry, I didnt mock up test tables for this, but I think you want to subquery against your holdsent table to get the count value into the main query, then use three parameters in your IIF() function. I didnt make a test case, but I think this will suit your needs:
SELECT IIF((isnull(holdsentCount.jobCount,0)>0, #STD, #RED) AS Colour
, jobs.job
, jobs.jobstatus
, jobs.client
, jobs.logdate
FROM jobs
JOIN clients
ON clients.client = jobs.client
LEFT JOIN (select holdsent.job
, count(*) as jobCount
from holdsent
group by holdsent.job ) as holdsentCount
ON holdsentCount.job = jobs.job
WHERE (jobs.jobstatus = 'HOLD' OR jobs.jobstatus = 'CLIHOLD')
Also, wrap the holdsentCount.jobCount with isnull() so that it returns 0 if it isn't returned in the subquery.
EDIT: I dont know what '#STD' or '#RED' are so I left them as-is.

Related

How to do operations between a column and a subquery

I would like to know how I can do operations between a column and a subquery, what I want to do is add to the field Subtotal what was obtained in the subquery Impuestos, the following is the query that I am using for this case.
Select
RC.PURCHID;
LRC.VALUEMST as 'Subtotal',
isnull((
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
), 0) Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;
Hope someone can give me some guidance when doing operations with subqueries.
A few disjointed facts that may help:
When a SELECT statement returns only one row with one column, you can enclose that statement in parenthesis and use it as a plain value. In your case, let's say that select sum(......= TOI1.DATAAREAID returns 500. Then, your outer select's second column is equivalent to isnull(500,0)
You mention in your question "subquery Impuestos". Keep in mind that, although you indeed used a subquery as we mentioned earlier, by the time it was enclosed in parentheses it is not treated as a subquery (more accurately: derived table), but as a value. Thus, the "Impuestos" is only a column alias at this point
I dislike and avoid subqueries before the from, makes things much harder to read. Here is a solution with apply which will keep your code mostly intact:
Select
RC.PURCHID,
LRC.VALUEMST as 'Subtotal',
isnull(subquery1.a, 0) as Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
outer apply
(
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
) as subquery1
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;

Pulling cost field from a sub-query

I wrote the following query to pull a unit cost from another table COSreport into my profitability query ProfitabilityReport and am having a problem with my sub-query.
select
i.tranid
, it.item_id
, it.displayname
, tl.Item_Count * -1 Unit_Qty
, case when tl.Item_Count=0 then 0
else ((tl.GROSS_AMOUNT * -1)/ Item_Count) * -1
end as PricePerUnit,
**(select sum(c.tranamt) from ns.COSreport c
inner join ns.ProfitabilityReport d
on c.InvoiceID = d.tranid
and c.item_id = d.item_id) as 'True Cost'**
, '0' 'Cost Per M'
from ns.tinvoice i
join ns.transaction_lines tl on i.transaction_id = tl.transaction_id
join ns.Customers cust on c.customer_id = i.ENTITY_ID
join ns.items it on it.item_id = tl.item_id
left join ns.ITEM_CLASSIFICATION it_class on it_class.list_id =
it.ITEM_CLASSIFICATION_ID
where list_item_name IS NOT NULL
and i.tranid = '1262INV'
I'm joining on both the invoice id and item id so that the proper cost is pulled across for the given invoice and item from COSReport.
However, the true cost is not coming up with the unit cost but instead is summing up the cost field for the entire table.
See below for example using invoice # 1262INV specified in the query above. The cost should be 1.04, .26, and 4 respectively vs 138m.
Any help getting this cleared up would be appreciated
I actually prefer using CTEs for readability. You can take your subquery, put it into a CTE, and then join it in your main query, but you'll want to add the tranid and item_id fields to the CTE so you can use them in your join.
EDIT: since you're using Azure SQL Server, you don't need the semicolon before the WITH.
WITH TrueCosts AS
(
SELECT
d.tranid
,d.item_id
,TrueCost = SUM(c.tranamt)
FROM ns.COSreport c
INNER JOIN ns.ProfitabilityReport d
ON c.InvoiceID = d.tranid
AND c.item_id = d.item_id
GROUP BY d.tranid
,d.item_id
)
SELECT
i.tranid
, it.item_id
, it.displayname
, tl.Item_Count * -1 Unit_Qty
, case when tl.Item_Count=0 then 0
else ((tl.GROSS_AMOUNT * -1)/ Item_Count) * -1
END as PricePerUnit
, tc.TrueCost AS 'True Cost'
, '0' AS 'Cost Per M'
FROM ns.tinvoice i
JOIN ns.transaction_lines tl on i.transaction_id = tl.transaction_id
JOIN ns.Customers c on c.customer_id = i.ENTITY_ID
JOIN ns.items it on it.item_id = tl.item_id
LEFT JOIN ns.ITEM_CLASSIFICATION it_class on it_class.list_id = it.ITEM_CLASSIFICATION_ID
LEFT JOIN TrueCosts tc ON tc.tranid = i.tranid AND tc.item_id = tl.item_id
WHERE list_item_name IS NOT NULL
AND i.tranid = '1262INV'
You have a couple of problems.
In your subquery you use the alias c for COSReport. You also use the alias c for customers in your outer query.
The bigger problem is that your subquery isn't correlated to your outer query at all. That's why it's summing up the entire table.
To correlate your subquery, you need to join (in the subquery) to one of the tables in the outer query. Not sure of your tables or data, but at a guess, I'd say you want to use ns.tinvoice i in a WHERE clause in your subquery.

SQL select results not appearing if a value is null

I am building a complex select statement, and when one of my values (pcf_auto_key) is null it will not disipaly any values for that header entry.
select c.company_name, h.prj_number, h.description, s.status_code, h.header_notes, h.cm_udf_001, h.cm_udf_002, h.cm_udf_008, l.classification_code
from project_header h, companies c, project_status s, project_classification l
where exists
(select company_name from companies where h.cmp_auto_key = c.cmp_auto_key)
and exists
(select status_code from project_status s where s.pjs_auto_key = h.pjs_auto_key)
and exists
(select classification_code from project_classification where h.pcf_auto_key = l.pcf_auto_key)
and pjm_auto_key = 11
--and pjt_auto_key = 10
and c.cmp_auto_key = h.cmp_auto_key
and h.pjs_auto_key = s.pjs_auto_key
and l.pcf_auto_key = h.pcf_auto_key
and s.status_type = 'O'
How does my select statement look? Is this an appropriate way of pulling info from other tables?
This is an oracle database, and I am using SQL Developer.
Assuming you want to show all the data that you can find but display the classification as blank when there is no match in that table, you can use a left outer join; which is much clearer with explicit join syntax:
select c.company_name, h.prj_number, h.description, s.status_code, h.header_notes,
h.cm_udf_001, h.cm_udf_002, h.cm_udf_008, l.classification_code
from project_header h
join companies c on c.cmp_auto_key = h.cmp_auto_key
join project_status s on s.pjs_auto_key = h.pjs_auto_key
left join project_classification l on l.pcf_auto_key = h.pcf_auto_key
where pjm_auto_key = 11
and s.status_type = 'O'
I've taken out the exists conditions as they just seem to be replicating the join conditions.
If you might not have matching data in any of the other tables you can make the other inner joins into outer joins in the same way, but be aware that if you outer join to project_status you will need to move the statatus_type check into the join condition as well, or Oracle will convert that back into an inner join.
Read more about the different kinds of joins.

Using MAX function in a subquery in Access

In Microsoft Access, I'm querying data from four tables and I'm using the MAX function to display the most recent records. The code below works but it's using two queries linked together. By using a sub-query, shown below with the full code, the code takes an hour to run, which is why I using two queries. Is there a better way of doing this?
QUERY 1
SELECT
a.office_id AS ofid,
rc.recorder_id AS recorder,
a.cust_name,
r.account_id,
rc.lpc_phone,
rc.device_serial,
rc.device_mfg,
rc.device_type
INTO RDS_INFO
FROM MaxDates
INNER JOIN (status AS s INNER JOIN ((config_recorder AS rc INNER JOIN recorders AS r ON rc.recorder_id = r.recorder_id)
INNER JOIN accounts AS a ON r.account_id = a.account_id) ON s.status = rc.row_status) ON (MaxDates.MaxOftrans_datetime = rc.trans_datetime) AND (MaxDates.recorder_id = rc.recorder_id)
WHERE (((rc.lpc_phone) Is Not Null
And (rc.lpc_phone)<>" "
And (rc.lpc_phone) Not Like "#,*")
AND ((rc.call_mode)="AN")
AND ((rc.row_status)=3
Or (rc.row_status)=11));
MaxDates Query:
SELECT
config_recorder.recorder_id,
Max(config_recorder.trans_datetime) AS MaxOftrans_datetime
FROM config_recorder
GROUP BY config_recorder.recorder_id;
Code used with the sub-query:
SELECT
a.cycle AS cyc,
a.office_id AS ofid,
rc.recorder_id AS recorder,
a.cust_name,
r.account_id,
rc.lpc_phone,
rc.device_serial,
rc.device_mfg,
rc.device_type
INTO Test
FROM config_recorder AS rc, status AS s, recorders AS r, accounts AS a
WHERE rc.recorder_id=r.recorder_id
AND r.account_id=a.account_id
AND ((rc.lpc_phone Is Not Null)
AND (rc.lpc_phone<>" ")
AND (rc.lpc_phone Not Like "#,*"))
AND ((rc.call_mode="AN")
AND (rc.row_status=s.status)
AND ((rc.row_status="3")
Or (rc.row_status="11")))
AND (rc.trans_datetime=(select max(r2.trans_datetime) from config_recorder r2 where r2.recorder_id = rc.recorder_id));
Thank you for your help.
You can consider changing the sub-query into an inline view and then joining it with other tables, as below:
SELECT
a.office_id AS ofid,
rc.recorder_id AS recorder,
a.cust_name,
r.account_id,
rc.lpc_phone,
rc.device_serial,
rc.device_mfg,
rc.device_type
INTO RDS_INFO
FROM status AS s
INNER JOIN
(config_recorder AS rc INNER JOIN recorders AS r ON rc.recorder_id = r.recorder_id)
ON s.status = rc.row_status
INNER JOIN accounts AS a
ON r.account_id = a.account_id
INNER JOIN
(SELECT
config_recorder.recorder_id,
Max(config_recorder.trans_datetime) AS MaxOftrans_datetime
FROM config_recorder
GROUP BY config_recorder.recorder_id) MaxDates
ON (MaxDates.MaxOftrans_datetime = rc.trans_datetime) AND (MaxDates.recorder_id = rc.recorder_id)
WHERE (((rc.lpc_phone) Is Not Null
And (rc.lpc_phone)<>" "
And (rc.lpc_phone) Not Like "#,*")
AND ((rc.call_mode)="AN")
AND ((rc.row_status)=3
Or (rc.row_status)=11));
References:
A related question on SO
Inline Views Versus Temp Tables on MSDN Magazine

sql join history table to active table SSRS report

I'm trying to pull results from a database (sql server 2005) which takes 4 tables:
Subscriber S, Member M, ClaimLines L, ClaimHistoryLines H
Query is as follows:
select S.SBSB_ID, M.MEME_NAME,
(CASE L.CLCL_ID WHEN '' THEN H.CLCL_ID ELSE L.CLCL_ID END) AS CLAIM_ID
FROM CMC_CDDL_CL_LINE L, CMC_MEME_MEMBER M LEFT OUTER JOIN CMC_CLDH_DEN_HIST H
ON H.MEME_CK = M.MEME_CK, CMC_SBSB_SUBSC S
WHERE
S.SBSB_ID = '120943270' AND
L.MEME_CK = M.MEME_CK AND
M.SBSB_CK = S.SBSB_CK
This query successfully pulls in the result rows from the ClaimLines L table but no results from the History table are shown. I'm not sure how to do this, any sql experts out there that can help would be great. -Thanks!
CMC_CDDL_CL_LINE L, CMC_MEME_MEMBER M LEFT OUTER JOIN CMC_CLDH_DEN_HIST H
don't mix obsolete implied join syntax with left join. They don't play well together. Use the correct ANSII standard join syntax. Infact stop using the obsolete syntax altogether.
This was a very silly mistake on my part. I neglected to think of using a UNION which solved my problem and allowed me to pull from both places into a single results set without creating massive duplicate rows. Glad someone pointed out the proper way to write sql using ANSII standards.
select S.SBSB_ID, M.MEME_NAME,
L.CLCL_ID AS CLAIM_ID
FROM
CMC_SBSB_SUBSC S INNER JOIN CMC_MEME_MEMBER M ON S.SBSB_CK = M.SBSB_CK
INNER JOIN CMC_CDDL_CL_LINE L ON L.MEME_CK = M.MEME_CK
WHERE
S.SBSB_ID = '120943270'
UNION
select S.SBSB_ID, M.MEME_NAME,
H.CLCL_ID AS CLAIM_ID
FROM
CMC_SBSB_SUBSC S INNER JOIN CMC_MEME_MEMBER M ON S.SBSB_CK = M.SBSB_CK
INNER JOIN CMC_CLDH_DEN_HIST H ON H.MEME_CK = M.MEME_CK
WHERE
S.SBSB_ID = '120943270'