How to use outer field name or alias in a nested subquery - sql

I would use the selected field Referencia in the subquery.
I have tried including the field name the alias, and table name but not works.
How I can achieve this ?
Thanks
SELECT * FROM
(
SELECT
articulos.Codigo AS Referencia,
articulos.Nombre AS Descripcion,
barras.Codigo AS [Codigo de Barras],
ROW_NUMBER() OVER (PARTITION BY articulos.Codigo ORDER BY
articulos.Codigo ASC) as cantidad,
articulos.Familia,
articulos.Marca,
categorias.Codigo as Categoria,
articulos.ImpuestoEspecial AS Ecotasa,
articulos.Fase,
articulos.Iva,
--
-- Tarifa1
( SELECT [Codigo],[EuroPrecio]
FROM [GES16100].[dbo].[Tarifas]
WHERE [Codigo] = 1 AND [Articulo] = <------- Here, Referencia
)AS T1,
articulos.Proveedor,
articulos.GUID_Registro
FROM [GES16100].[dbo].[Articulos] as articulos
FULL JOIN [GES16100].[dbo].[Barras] as barras
ON articulos.Codigo = barras.Articulo
FULL JOIN [GES16100].[dbo].[Categorias_Asignaciones] catasignaciones
ON catasignaciones.GUID_RegistroFichero =articulos.GUID_Registro
FULL JOIN [GES16100].[dbo].[CategoriasFicheros] categorias
ON categorias.GUID_Registro = catasignaciones.GUID_Categoria
)AS supersub
WHERE supersub.cantidad = 1

Use table aliases and qualified column names whenever you have more than one table in a query.
Second, your subquery will not work because it returns two columns where one is expected.
For your example, I am guessing:
( SELECT t.EuroPrecio
FROM [GES16100].[dbo].[Tarifas] t
WHERE t.Codigo = 1 AND t.Articulo = a.Codigo
) AS T1,
You cannot use the column alias Referencias because it is defined in the same SELECT. Just use the column it is refering to.

Related

must appear in the group by clause in sql

I have a sql statement and I am trying to add order by, when I add order statement I get an error
ERROR: column "items.id" must appear in the GROUP BY clause or be used in an aggregate function
My query is.
WITH "has_children_cte"
AS (SELECT DISTINCT "parent_id" AS "item_id",
1 AS "has_children"
FROM "items")
SELECT "item_category_id",
Count(*) AS "count"
FROM "items"
INNER JOIN "items" AS "root_item"
ON ( "root_item"."id" = "items"."root_id" )
LEFT JOIN "item_types"
ON ( "items"."item_type_id" = "item_types"."id" )
LEFT JOIN "item_categories"
ON ( "item_categories"."id" = "item_types"."item_category_id" )
INNER JOIN "order_items"
ON ( "items"."order_item_id" = "order_items"."id" )
INNER JOIN "orders"
ON ( "order_items"."order_id" = "orders"."id" )
LEFT JOIN "has_children_cte"
ON ( "items"."id" = "has_children_cte"."item_id" )
WHERE ( ( "items"."parent_id" IS NULL )
AND ( "items"."state" != 'discarded' ) )
GROUP BY "item_category_id"
ORDER BY "items"."id";
I have add the ORDER BY "items"."id";
Then I get this error. When I try to add items.id into group by I got bad results.
Unfortunately I am unable to handle this error.
The ORDER BY (logically) takes place after the aggregation. And after the aggregation, "items"."id" is not available in each row.
So just use an aggregation function:
ORDER BY MIN("items"."id")

INNER JOINING THE TABLE ITSELF GIVES No column name was specified for column 2

SELECT *
FROM
construction AS T2
INNER JOIN
(
SELECT project,MAX(report_date)
FROM construction
GROUP BY project
) AS R
ON T2.project=R.project AND T2.report_date=R.report_date
getting this error. plz help
No column name was specified for column 2 of 'R'
You need to add alias for MAX(report_date):
SELECT *
FROM construction AS T2
INNER JOIN
(
SELECT project,MAX(report_date) AS report_date
FROM construction
GROUP BY project
) AS R
ON T2.project = R.project
AND T2.report_date = R.report_date;
In SQL Server you can use syntax:
SELECT *
FROM construction AS T2
INNER JOIN
(
SELECT project,MAX(report_date)
FROM construction
GROUP BY project
) AS R(project, report_date)
ON T2.project = R.project
AND T2.report_date = R.report_date;
You should specific the MAX(report_date) with an alias report_date.
Because your table R have two columns project,MAX(report_date).
You are getting this error because you have not specified column name for inner query
You have to write your query as
SELECT *
FROM construction
INNER JOIN
(
SELECT project,MAX(report_date)"Max_ReportDate"
FROM construction
GROUP BY project
) Max_construction
ON construction.project = Max_construction .project
AND construction.report_date = Max_construction .Max_ReportDate

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

I got an error
Column 'Employee.EmpID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
SQL code:
with cte(stu_id,term_cd, spcl_cd ) as
(
Select
zt.[STU_ID], zt.TERM_CD, zt.SPCL_CD
From
SR0TZT(nolock) zt
Inner Join
(Select
STU_ID, MIN(TERM_SEQ_NUM) MinPoint, SPCL_CD
From SR0TZT
Group By STU_ID) tbl1 On zt.STU_ID = tbl1.STU_ID
Where
tbl1.MinPoint = zt.TERM_SEQ_NUM
and zt.STU_ID = '202716354'
and tbl1.SPCL_CD = zt.SPCL_CD
)
SELECT
zt.[STU_ID], zt.[TERM_CD], zt.[SPCL_CD],
zt.[SPCL_STRT_TERM], zt.TERM_SEQ_NUM, t.term_id
FROM
SR0TZT zt
JOIN
cte ON zt.STU_ID = cte.stu_id
WHERE
zt.STU_ID = '202716354'
Condition is:
For each unique combination of TZT.STU_ID and TZT.SPCL_CD where TZT.COLL_CD = '', display the TZT.TERM_CD with the minimum TZT.TERM_SEQ_NUM.
For UID 202716354, based on the above rule, the value of this column is incorrect for both specialization codes.
Not sure I understand why you are getting an error for 'Employee.EmpID' as it doesn't appear in your query.
At first look I can see that the following part of your SQL code (the derived table 'tbl1')...
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID
..is incorrect and would cause a similar error because SPCL_CD isn't used in an aggregate function (such as MIN) or in the GROUP BY. You should change it to:-
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID, SPCL_CD
And that should solve your problem.
Your problem is in this below script:
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID
It should be:
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID, SPCL_CD
Every column that you put in select, you should put them too in group by.

Providing Language FallBack In A SQL Select Statement

I have a table that represents an Object. It has many columns but also fields that require language support.
For simplicity let's say I have 3 tables:
MainObjectTable
LanguageDependantField1
LanguageDependantField2.
MainObjectTable has a PK int called ID, and both LanguageDependantTables have a foreign key link back to the MainObjectTable along with a language code and the date they were added.
I've created a stored procedure that accepts the MainObjectTable ID and a Language. It will return a single row containing the most recent items from the language tables. The select statement looks like
SELECT
MainObjectTable.VariousColumns,
LanguageDependantField1.Description,
LanguageDependantField2.SomeOtherText
FROM
MainObjectTable
OUTER APPLY
(SELECT TOP 1 LanguageDependantField1.Description
FROM LanguageDependantField1
WHERE LanguageDependantField1.MainObjectTable_ID = MainObjectTable.ID
AND LanguageDependantField1.Language_ID = #language
ORDER BY
LanguageDependantField1.[Default], LanguageDependantField1.CreatedDate DESC) LanguageDependantField1
OUTER APPLY
(SELECT TOP 1 LanguageDependantField2.SomeOtherText
FROM LanguageDependantField2
WHERE LanguageDependantField2.MainObjectTable_ID = MainObjectTable.ID
AND LanguageDependantField2.Language_ID = #language
ORDER BY
LanguageDependantField2.[Default] DESC, LanguageDependantField2.CreatedDate DESC) LanguageDependantField2
WHERE
MainObjectTable.ID = #MainObjectTableID
What I want to add is the ability to fallback to a default language if a row isn't found in the specified language. Let's say we use "German" as the selected language. Is it possible to return an English row from LanguageDependantField1 if the German does not exist presuming we have #fallbackLanguageID
Also am I right to use OUTER APPLY in this scenario or should I be using JOIN?
Many thanks for your help.
Try this:
SELECT MainObjectTable.VariousColumns,
COALESCE(PrefLang.Description,Fallback.Description,'Not Found Desc')
as Description,
COALESCE(PrefLang.SomeOtherText,FallBack.SomeOtherText,'Not found')
as SomeOtherText
FROM MainObjectTable
LEFT JOIN
(SELECT TOP 1 pl.Description,pl.SomeOtherText
FROM LanguageDependantField1 pl
WHERE pl.MainObjectTable_ID = MainObjectTable.ID
AND pl.Language_ID = #language
ORDER BY
pl.[Default], pl.CreatedDate DESC)
PrefLang ON 1=1
LEFT JOIN
(SELECT TOP 1 fb.Description,fb.SomeOtherText
FROM LanguageDependantField1 fb
WHERE fb.MainObjectTable_ID = MainObjectTable.ID
AND fb.Language_ID = #fallbackLanguageID
ORDER BY
fb.[Default], fb.CreatedDate DESC)
Fallback ON 1=1
WHERE
MainObjectTable.ID = #MainObjectTableID
Basically, make two queries, one to the preferred language and one to English (Default). Use the LEFT JOIN, so if the first one isn't found, the second query is used...
I don't have your actual tables, so there might be a syntax error in above, but hope it gives you the concept you want to try...
Yes, the use of Outer Apply is correct if you want to correlate the MainObjectTable table rows to the inner queries. You cannot use Joins with references in the derived table to the outer table. If you wanted to use Joins, you would need to include the joining column(s) and in this case pre-filter the results. Here is what that might look like:
With RankedLanguages As
(
Select LDF1.MainObjectTable_ID, LDF1.Language_ID, LDF1.Description, LDF1.SomeOtherText, ...
, Row_Number() Over ( Partition By LDF1.MainObjectTable_ID, LDF1.Language_ID
Order By LDF1.[Default] Desc, LDF1.CreatedDate Desc ) As Rnk
From LanguageDependantField1 As LDF1
Where LDF1.Language_ID In( #languageId, #defaultLanguageId )
)
Select M.VariousColumns
, Coalesce( SpecificLDF.Description, DefaultLDF.Description ) As Description
, Coalesce( SpecificLDF.SomeOtherText, DefaultLDF.SomeOtherText ) As SomeOtherText
, ...
From MainObjectTable As M
Left Join RankedLanguages As SpecificLDF
On SpecificLDF.MainObjectTable_ID = M.ID
And SpecifcLDF.Language_ID = #languageId
And SpecifcLDF.Rnk = 1
Left Join RankedLanguages As DefaultLDF
On DefaultLDF.MainObjectTable_ID = M.ID
And DefaultLDF.Language_ID = #defaultLanguageId
And DefaultLDF.Rnk = 1
Where M.ID = #MainObjectTableID

Limit join to one row

I have the following query:
SELECT sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount, 'rma' as
"creditType", "Clients"."company" as "client", "Clients".id as "ClientId", "Rmas".*
FROM "Rmas" JOIN "EsnsRmas" on("EsnsRmas"."RmaId" = "Rmas"."id")
JOIN "Esns" on ("Esns".id = "EsnsRmas"."EsnId")
JOIN "EsnsSalesOrderItems" on("EsnsSalesOrderItems"."EsnId" = "Esns"."id" )
JOIN "SalesOrderItems" on("SalesOrderItems"."id" = "EsnsSalesOrderItems"."SalesOrderItemId")
JOIN "Clients" on("Clients"."id" = "Rmas"."ClientId" )
WHERE "Rmas"."credited"=false AND "Rmas"."verifyStatus" IS NOT null
GROUP BY "Clients".id, "Rmas".id;
The problem is that the table "EsnsSalesOrderItems" can have the same EsnId in different entries. I want to restrict the query to only pull the last entry in "EsnsSalesOrderItems" that has the same "EsnId".
By "last" entry I mean the following:
The one that appears last in the table "EsnsSalesOrderItems". So for example if "EsnsSalesOrderItems" has two entries with "EsnId" = 6 and "createdAt" = '2012-06-19' and '2012-07-19' respectively it should only give me the entry from '2012-07-19'.
SELECT (count(*) * sum(s."price")) AS amount
, 'rma' AS "creditType"
, c."company" AS "client"
, c.id AS "ClientId"
, r.*
FROM "Rmas" r
JOIN "EsnsRmas" er ON er."RmaId" = r."id"
JOIN "Esns" e ON e.id = er."EsnId"
JOIN (
SELECT DISTINCT ON ("EsnId") *
FROM "EsnsSalesOrderItems"
ORDER BY "EsnId", "createdAt" DESC
) es ON es."EsnId" = e."id"
JOIN "SalesOrderItems" s ON s."id" = es."SalesOrderItemId"
JOIN "Clients" c ON c."id" = r."ClientId"
WHERE r."credited" = FALSE
AND r."verifyStatus" IS NOT NULL
GROUP BY c.id, r.id;
Your query in the question has an illegal aggregate over another aggregate:
sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount
Simplified and converted to legal syntax:
(count(*) * sum(s."price")) AS amount
But do you really want to multiply with the count per group?
I retrieve the the single row per group in "EsnsSalesOrderItems" with DISTINCT ON. Detailed explanation:
Select first row in each GROUP BY group?
I also added table aliases and formatting to make the query easier to parse for human eyes. If you could avoid camel case you could get rid of all the double quotes clouding the view.
Something like:
join (
select "EsnId",
row_number() over (partition by "EsnId" order by "createdAt" desc) as rn
from "EsnsSalesOrderItems"
) t ON t."EsnId" = "Esns"."id" and rn = 1
this will select the latest "EsnId" from "EsnsSalesOrderItems" based on the column creation_date. As you didn't post the structure of your tables, I had to "invent" a column name. You can use any column that allows you to define an order on the rows that suits you.
But remember the concept of the "last row" is only valid if you specifiy an order or the rows. A table as such is not ordered, nor is the result of a query unless you specify an order by
Necromancing because the answers are outdated.
Take advantage of the LATERAL keyword introduced in PG 9.3
left | right | inner JOIN LATERAL
I'll explain with an example:
Assuming you have a table "Contacts".
Now contacts have organisational units.
They can have one OU at a point in time, but N OUs at N points in time.
Now, if you have to query contacts and OU in a time period (not a reporting date, but a date range), you could N-fold increase the record count if you just did a left join.
So, to display the OU, you need to just join the first OU for each contact (where what shall be first is an arbitrary criterion - when taking the last value, for example, that is just another way of saying the first value when sorted by descending date order).
In SQL-server, you would use cross-apply (or rather OUTER APPLY since we need a left join), which will invoke a table-valued function on each row it has to join.
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989
-- CROSS APPLY -- = INNER JOIN
OUTER APPLY -- = LEFT JOIN
(
SELECT TOP 1
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
,MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
FROM T_MAP_Contacts_Ref_OrganisationalUnit
WHERE MAP_CTCOU_SoftDeleteStatus = 1
AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID
/*
AND
(
(#in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo)
AND
(#in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
) AS FirstOE
In PostgreSQL, starting from version 9.3, you can do that, too - just use the LATERAL keyword to achieve the same:
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989
LEFT JOIN LATERAL
(
SELECT
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
,MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
FROM T_MAP_Contacts_Ref_OrganisationalUnit
WHERE MAP_CTCOU_SoftDeleteStatus = 1
AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID
/*
AND
(
(__in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo)
AND
(__in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
LIMIT 1
) AS FirstOE
Try using a subquery in your ON clause. An abstract example:
SELECT
*
FROM table1
JOIN table2 ON table2.id = (
SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE
...