Joining a group by subquery with substr columns - sql

I am trying to join a group by subquery with another table but am running in to issues since the subquery contains aliases which are only valid within the subquery. The issue is that the AREA table only has the 3 digit locker id embedded as part of a longer string in the ARE_CODE column which is why I am using substr. Here is the group by subquery:
SELECT SUBSTR(ARE_CODE,0,3) AS "Locker", COUNT(ARE_UID) AS "Qty"
FROM AREA
WHERE SUBSTR(ARE_CODE,0,1)='L'
GROUP BY SUBSTR(ARE_CODE,0,3)
It runs fine on its own - the problem is that I am trying to join this with another table in the main query. The alias is only valid within the subquery itself and can't be referenced as I did below. I have also tried joining the substr function directly but that doesn't work either.
SELECT P.Locker, P.Permit, L.Qty
FROM PERMITS P
INNER JOIN (SELECT SUBSTR(ARE_CODE,0,3) AS "Locker", COUNT(ARE_UID) AS "Qty"
FROM AREA_LKP
WHERE SUBSTR(ARE_CODE,0,1)='L'
GROUP BY SUBSTR(ARE_CODE,0,3) L ON L.Locker = P.Locker
Any suggestions on how to work around this issue?

You just need to remove the double quotes from the alias as they makes the alias case sensistive and you must have to use them with double quotes wherever you want to use them in your query with exact case.
So better not to use the double quotes for alias untill and unless you want to give the case sensitive name or want space in the alias.
SELECT P.Locker, P.Permit, L.Qty
FROM PERMITS P
INNER JOIN (SELECT SUBSTR(ARE_CODE,0,3) AS Locker, COUNT(ARE_UID) AS Qty
FROM AREA_LKP
WHERE SUBSTR(ARE_CODE,0,1)='L'
GROUP BY SUBSTR(ARE_CODE,0,3) L ON L.Locker = P.Locker

The issue are the double quotes. But your query has other eccentricities:
In strings, the first character is at 1, not 0 (although 0 is allowed).
LIKE is a good way to do string comparisons.
So:
SELECT P.Locker, P.Permit, L.Qty
FROM PERMITS P INNER JOIN
(SELECT SUBSTR(ARE_CODE, 1, 3) AS Locker, COUNT(*) AS Qty
FROM AREA_LKP
WHERE ARE_CODE LIKE 'L%'
GROUP BY SUBSTR(ARE_CODE, 1, 3)
) L
ON L.Locker = P.Locker;
I should note that LIKE permits the use of an index on the column, but SUBSTR() generally prevents that.

Why you`re set the alias of the table at the end of the subquery?
INNER JOIN (SELECT SUBSTR(ARE_CODE,0,3) AS "Locker", COUNT(ARE_UID) AS "Qty"
FROM AREA_LKP
WHERE SUBSTR(ARE_CODE,0,1)='L'
GROUP BY SUBSTR(ARE_CODE,0,3) L
Try:
INNER JOIN (SELECT SUBSTR(ARE_CODE,0,3) AS "Locker", COUNT(ARE_UID) AS "Qty"
FROM AREA_LKP L
WHERE SUBSTR(ARE_CODE,0,1)='L'
GROUP BY SUBSTR(ARE_CODE,0,3)
For sharing expressions between different statements take a look at the with-statement:
https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/with.html
Finally, are you sure that:
L.Locker = P.Locker
Can be evaluated as expected? So is the substringged value of L.Locker same as P.Locker?

Related

When I try to get MIN value of manufactured parts I get (Only one expression ... when the subquery is not introduced with EXISTS)

I try to get MIN value of manufactured parts grouped by project like so:
This is my query:
SELECT
proinfo.ProjectN
,ProjShipp.[Parts]
,ProjShipp.Qty AS 'Qty Total'
,Sum(DailyProduction.Quantity) AS 'Qty Manufactured'
,(SELECT DailySumPoteau.IdProject, MIN(DailySumPoteau.DailySum)
FROM (SELECT PShipp.IdProject, SUM(DailyWelding.Quantity) DailySum
FROM DailyWeldingPaintProduction DailyWelding
INNER JOIN ProjectShipping PShipp ON PShipp.id=DailyWelding.FK_idPartShip
WHERE PShipp.id=ProjShipp.id
GROUP BY PShipp.id,PShipp.IdProject)DailySumPoteau
GROUP BY DailySumPoteau.IdProject ) AS 'Qt Pole'
FROM [dbo].[DailyWeldingPaintProduction] DailyProduction
INNER join ProjectShipping ProjShipp on ProjShipp.id=DailyProduction.FK_idPartShip
inner join ProjectInfo proinfo on proinfo.id=IdProject
GROUP By proinfo.id
,proinfo.ProjectN
,ProjShipp.[Parts]
,ProjShipp.Qty
,ProjShipp.[Designation]
,ProjShipp.id
I have three tables:
01 - ProjectInfo: it stores information about the project:
02 - ProjectShipping: it stores information about the parts and it has ProjectInfoId as foreign key:
03 - DailyWeldingPaintProduction: it stores information about daily production and it has ProjectShippingId as foreign key:
but when I run it I get this error:
Msg 116, Level 16, State 1, Line 13
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
How can I solve this problem?.
From your target results, I suspect that you want a window MIN(). Assuming that your query works and generates the correct results when the subquery is removed (column QtPole left apart), that would be:
SELECT pi.ProjectN, ps.[Parts], ps.Qty AS QtyTotal,
SUM(dp.Quantity) AS QtyManufactured,
MIN(SUM(dp.Quantity)) OVER(PARTITION BY pi.ProjectN) AS QtPole
ps.Designation
FROM [dbo].[DailyWeldingPaintProduction] dp
INNER join ProjectShipping ps on ps.id=dp.FK_idPartShip
INNER join ProjectInfo pi on pi.id=IdProject
GROUP BY pi.id, pi.ProjectN, ps.[Parts], ps.Qty, ps.Designation, ps.id
Side note: don't use single quotes for identifiers; they should be reserved for literal strings only. Use the proper quoting character for your database (in SQL Server: square brackets) - or better yet, use identifiers that do not require being quoted.
Formulating the query in the way you have done is not necessarily the best solution. As the other solution mentions, the best method in this instance is probably to use a window function / OVER. But since this can depend on indexes, and also to understand what went wrong, I will give you the way to fix the original query.
The issue with your query is that it has a correlated subquery in the SELECT which returns two values. What you are trying to do can be done in RDBMSs that support row constructors, unfortunately SQl Server is not one of them.
What you are trying to get at here is to get a whole resultset per row of the table.
The correct syntax for your query is to APPLY the resultset of the subquery for every row. You can CROSS APPLY in this instance because you are guaranteed a result anyway due to the correlation:
SELECT
proinfo.ProjectN
,ProjShipp.[Parts]
,ProjShipp.Qty AS 'Qty Total'
,Sum(DailyProduction.Quantity) AS 'Qty Manufactured'
,QtPole.IdProject
,QtPole.MinDailySum
FROM [dbo].[DailyWeldingPaintProduction] DailyProduction
INNER join ProjectShipping ProjShipp on ProjShipp.id=DailyProduction.FK_idPartShip
inner join ProjectInfo proinfo on proinfo.id=ProjShipp.IdProject
CROSS APPLY (
SELECT DailySumPoteau.IdProject, MIN(DailySumPoteau.DailySum) MinDailySum
FROM (SELECT DailyWelding.FK_idPartShip IdProject, SUM(DailyWelding.Quantity) DailySum
FROM DailyWeldingPaintProduction DailyWelding
WHERE DailyWelding.FK_idPartShip=ProjShipp.id
GROUP BY DailyWelding.FK_idPartShip) DailySumPoteau
GROUP BY DailySumPoteau.IdProject
) AS QtPole
GROUP By proinfo.id
,proinfo.ProjectN
,ProjShipp.[Parts]
,ProjShipp.Qty
,ProjShipp.[Designation]
,ProjShipp.id
,QtPole.IdProject
,QtPole.MinDailySum
I have taken the liberty of cleaning up the subquery by removing the unnecessary ProjectShipping reference. Note that the addition of grouping columns here does not matter because of the correlation to ProjShipp.Id
Note also that depending on indexes and density and such like, it may be better to formulate the subquery as a JOIN instead, with the correlation on the outside in the ON. You would need to modify the grouping in that case.

Error in using subquery in access join query

I need to use the result of a query as a lookup field for another query. What I tried was using a sub query aliased as something, but finally I got some error saying "enter parameter value" for variz.variz and Y.varizname.
I've searched in forums, but I can't find any similar problem.
SELECT sahmeharkas.attrib,
[sahmeharkas]![expenseper] AS Expense,
variz.variz
FROM sahmeharkas
LEFT JOIN
(SELECT variz.varizname FROM variz GROUP BY variz.varizname) as Y
ON sahmeharkas.attrib = Y.variz.varizname
The table variz does not exist outside of the subquery; you should instead use the subquery alias as the table qualifier, e.g.:
select s.attrib, s.expenseper as expense, y.variz
from
sahmeharkas s left join
(select v.variz, v.varizname from variz v group by v.variz, v.varizname) y on
s.attrib = y.varizname

Using trunc and concatenate command with Join

select EDR_Process_Time, MSISDN1, Total_payment/Total_data_MB from
(
select trunc(M_MOBILEMV.Q_RA_EDR_DETAILS_V.process_time) as EDR_Process_Time, M_MOBILEMV.Q_RA_EDR_DETAILS_V.MSISDN as MSISDN1, trunc(M_MOBILEMV.Q_RA_CDR_DETAILS_V.CDR_start_Date), M_MOBILEMV.Q_RA_CDR_DETAILS_V.served_msisdn, sum(M_MOBILEMV.Q_RA_CDR_DETAILS_V.charge_fee_1) as Charge_fee_CDR,
sum(M_MOBILEMV.Q_RA_EDR_DETAILS_V.charge_fee/100) as Total_Payment,
sum(M_MOBILEMV.Q_RA_EDR_DETAILS_V.amount/1048576) as Total_data_MB,
from (M_MOBILEMV.Q_RA_EDR_DETAILS_V
left join M_MOBILEMV.Q_RA_CDR_DETAILS_V on concat(trunc(M_MOBILEMV.Q_RA_EDR_DETAILS_V.process_time), M_MOBILEMV.Q_RA_EDR_DETAILS_V.MSISDN) = concat(trunc(M_MOBILEMV.Q_RA_CDR_DETAILS_V.CDR_start_date), M_MOBILEMV.Q_RA_CDR_DETAILS_V.served_MSISDN))
group by trunc(M_MOBILEMV.Q_RA_EDR_DETAILS_V.Process_time), M_MOBILEMV.Q_RA_EDR_DETAILS_V.MSISDN
group by trunc(M_MOBILEMV.Q_RA_CDR_DETAILS_V.CDR_start_Date), M_MOBILEMV.Q_RA_CDR_DETAILS_V.Served_MSISDN
)
Syntax of functions is wrong. Use trunc function as trunc(M_MOBILEMV.Q_RA_EDR_DETAILS_V.process_time). Usege of sum is wrong too. You also should change them to sum(M_MOBILEMV.Q_RA_CDR_DETAILS_V.charge_fee_1.
First, wrong syntax at M_MOBILEMV.Q_RA_EDR_DETAILS_V.sum((charge_fee)/100) and other similar expressions.
If you want sum of charge_fee/100 column of the M_MOBILEMV.Q_RA_EDR_DETAILS_V table (view) it must
be
sum(M_MOBILEMV.Q_RA_EDR_DETAILS_V.charge_fee/100)
Next, you can not use an alias in the same SELECT list where it was introduced. Total_Payment and Total_data_MB should only apprear in expressions at outer SELECT.
Assign aliases to the every expression of the inner select, an alias to the inner select itself and use list of qualified names and expresions using those names instead of * in the outer select.
Also, it looks like GROUP BY is missing.
select t.process_time, t.MSISDN, t.sum1,
t.Total_Payment,
t.Total_data_MB,
t.Total_Payment/t.Total_data_MB as cost_per_MB
from (
select
M_MOBILEMV.Q_RA_EDR_DETAILS_V.process_time,
M_MOBILEMV.Q_RA_EDR_DETAILS_V.MSISDN,
sum(M_MOBILEMV.Q_RA_CDR_DETAILS_V.charge_fee_1) as sum1,
(coalesce(sum(M_MOBILEMV.Q_RA_CDR_DETAILS_V.charge_fee_1),0) + coalesce(sum(M_MOBILEMV.Q_RA_EDR_DETAILS_V.charge_fee/100),0)) as Total_Payment,
sum(M_MOBILEMV.Q_RA_EDR_DETAILS_V.amount)/1048576 as Total_data_MB
-- Don't you mean
--GROUP BY M_MOBILEMV.Q_RA_EDR_DETAILS_V.process_time, M_MOBILEMV.Q_RA_EDR_DETAILS_V.MSISDN
from (M_MOBILEMV.Q_RA_EDR_DETAILS_V
left join M_MOBILEMV.Q_RA_CDR_DETAILS_V on concat(trunc(M_MOBILEMV.Q_RA_EDR_DETAILS_V.process_time), M_MOBILEMV.Q_RA_EDR_DETAILS_V.MSISDN) = concat(trunc(M_MOBILEMV.Q_RA_CDR_DETAILS_V.CDR_start_date), M_MOBILEMV.Q_RA_CDR_DETAILS_V.served_MSISDN)
) t
)

conditional IIF in a JOIN

I have the next data base:
Table Bill:
Table Bill_Details:
And Table Type:
I want a query to show this result:
The query as far goes like this:
SELECT
Bill.Id_Bill,
Type.Id_Type,
Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT,
Bill.Date2,
Bill.Comt
FROM Type
RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type
ORDER BY Bill.Id_Bill, Type.Id_Type;
With this result:
I'm not sure how to deal or how to include this:
Type.600,
Type."TOTAL",
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" ),
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" )
The previous code is the responsable of include new data in some fields, since all of the other fields will carry the same data of the upper register. I'll apreciate some sugestions to acomplish this.
Here is a revised version of the UNION which you removed from the question. The original query was a good start, but you just did not provide sufficient details about the error or problem you were experiencing. My comments were not meant to have you remove the problem query, only that you needed to provide more details about the error or problem. In the future if you have a UNION, make sure the each query of the UNION works separately. Then you could debug problems easier, one step at a time.
Problems which I corrected in the second query of the UNION:
Removed reference to table [Type] in the query, since it was not part of the FROM clause. Instead, I replaced it with a literal value.
Fixed FROM clause to join both [Bill] and [Bill_Details] tables. You had fields from both tables, so why would you not join on them just like in the first query of the UNION?
Grouped on all fields from table [Bill] referenced in the SELECT clause. You must either group on all fields, or include them in aggregate expressions like Sum() or First(), etc.
Replaced empty strings with Nulls for the False cases on Iif() statements.
SELECT
Bill.Id_Bill, Type.Id_Type, Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM
Type RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type;
UNION
SELECT
Bill.Id_Bill, 600 As Id_Type, "TOTAL" As Info,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Deb,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill
GROUP BY Bill.Id_Bill, Bill.NIT, Bill.Date2, Bill.Comt;

Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

I'm trying to select a bunch of patients with their unit and division and I want to group the result by unit name, but this code doesn't execute and gives the error as the topic of this question.
SELECT TOP (100) PERCENT
Pat.PatName AS Name,
srvDiv.sgMType AS Perkhidmatan,
Pat.PatMRank AS Pangkat,
Pat.PatMilitaryID AS [No# Tentera],
unt.untName AS Unit,
fct.pesStatusCode as StatusCode,
fct.pesSignedDate AS SignedDate
FROM dbo.FactPES AS fct INNER JOIN
dbo.DimPatient AS Pat ON fct.pesPatID = Pat.PatID LEFT OUTER JOIN
dbo.DimUnit AS unt ON fct.pesUnitID = unt.untID LEFT OUTER JOIN
dbo.DimServiceDiv AS srvDiv ON fct.pesServiceDivID = srvDiv.sgID
GROUP BY unt.untName
HAVING (deas.diDate BETWEEN
CONVERT(DATETIME, #FromDate, 102)
AND
CONVERT(DATETIME, #ToDate, 102))
I assume it's because unt.UntName is in my left join so I can't use it outside the join maybe ? I'm a bit confused because when I put it like this it works:
GROUP BY unt.untName, Pat.PatName, srvDiv.sgMType,
Pat.PatMRank, Pat.PatMilitaryID, unt.untName,
fct.pesStatusCode, fct.pesSignedDate
Any help is appreciated
First, please don't use TOP (100) PERCENT; it hurts even to read.
Second, your query contains no aggregate function, no SUM or COUNT for example. When you say you want to "group by unit name", I suspect you may simply want the results sorted by unit name. In that case, you want ORDER BY instead. (The advice from other to study what group by does is well taken.)
Finally, you might not need those CONVERT functions at the end, depending on your DBMS.
Whenever you use a GROUP BY - it should be present in the SELECT statement as a column. And if you do not want to contain it in a GROUP BY use it as an AGGREGATE column in SELECT.
So now in your case the second GROUP BY stated in your question will work.
Read this to understand more about GROUP BY