The right way to use aliases in SQL - sql

I have question about SQL. Below I have query from order controller in Prestashop 1.6. The question is. Why I have two aliases for ps_orders ? Please check below query:
SELECT SQL_NO_CACHE SQL_CALC_FOUND_ROWS
a.`id_order`,
`reference`,
`total_paid_tax_incl`,
`payment`,
a.`date_add` AS `date_add`,
a.id_currency,
a.id_order AS id_pdf,
CONCAT(LEFT(c.`firstname`, 1), '. ', c.`lastname`) AS `customer`,
osl.`name` AS `osname`,
os.`color`,
IF(
(SELECT COUNT(id_customer)
FROM `ps_orders` so
WHERE so.id_customer = a.id_customer) = 1, "Tak", "Nie") AS first_order,
IF(
(SELECT so.id_order
FROM `ps_orders` so
WHERE so.id_customer = a.id_customer
AND so.id_order < a.id_order
LIMIT 1) > 0, 0, 1) AS NEW,
country_lang.name AS cname,
IF(a.valid, 1, 0) badge_success
FROM `ps_orders` a
LEFT JOIN `ps_customer` c ON (c.`id_customer` = a.`id_customer`)
LEFT JOIN `ps_address` address ON address.id_address = a.id_address_delivery
LEFT JOIN `ps_country` country ON address.id_country = country.id_country
LEFT JOIN `ps_country_lang` country_lang ON (country.`id_country` = country_lang.`id_country`
AND country_lang.`id_lang` = 6)
LEFT JOIN `ps_order_state` os ON (os.`id_order_state` = a.`current_state`)
LEFT JOIN `ps_order_state_lang` osl ON (os.`id_order_state` = osl.`id_order_state`
AND osl.`id_lang` = 6)
WHERE 1
ORDER BY a.`id_order` DESC
LIMIT 0, 50
Once I have a.id_order in another so.id_order. Maybe I am wrong but I thing that is the same ps_orders. First declaration is ps_orders so and the second ps_orders a ? Why someone use two aliases to the same table ?

General queries are like:
SELECT
A.SomeColumn
FROM
YourTable A
If you have subqueries then
SELECT
A.SomeColumn,
(SELECT SomeOtherColumn FROM AnotherTable) ColumnAlias
FROM
YourTable A
And if you have a subquery with the same table, you might want to use different aliases to distinguish them!
SELECT
A.SomeColumn,
(SELECT B.SomeColumn FROM YourTable B) ColumnAlias
FROM
YourTable A
Columns from tables referenced in subqueries cannot be referenced outside:
SELECT
A.SomeColumn,
(SELECT B.SomeOtherColumn FROM YourTable B) ColumnAlias,
B.SomeOtherColumn -- What table is B here? Outside scope!
FROM
YourTable A
But columns from the outside can be referenced inside!
SELECT
A.SomeColumn,
(SELECT B.SomeOtherColumn FROM YourTable B WHERE B.SomeOtherColumn = A.SomeColumn) ColumnAlias,
FROM
YourTable A
PD: I'm assuming in these examples that the subquery returns 1 row.

One alias is for the main query, and the other is used in the sub queries.
The main query and each subquery must use an alias since they both are referencing the same table as the main query.
That's the only way the sub query can relate to the records from the same table used in the main query - Just like when you do a self join - Once you have the same table (or view) more than once in your query, you must use different aliases for it.

Related

Joining Onto Partition Statement HANA SQL

I am trying to join two tables to the following query:
SELECT "NUMBER",
"U_ANALYZED_DATE",
"DV_SALES_ACCOUNT",
"U_USD_TOTAL_POTENTIAL_NNACV"
FROM
(select *, row_number() over ( partition by "DV_SALES_ACCOUNT" order by "U_ANALYZED_DATE" desc ) rownum
from "SURF_RT"."SALES_REQUEST")
WHERE rownum = 1
AND "DV_SALES_CATEGORY" = 'Compliance'
AND "DV_STATE" NOT IN ('Closed Canceled')
AND (YEAR("U_ANALYZED_DATE") = '2019' AND MONTH("U_ANALYZED_DATE") IN ('10','11','12')
OR YEAR("U_ANALYZED_DATE") = '2020' AND MONTH("U_ANALYZED_DATE") IN ('1','2','3'))
AND "U_USD_TOTAL_POTENTIAL_NNACV" > 0
ORDER BY "U_ANALYZED_DATE" desc
The tables should be joined as follows:
JOIN "SURF_RT"."SALES_ACCOUNT" on "SURF_RT"."SALES_ACCOUNT"."NAME" = "SURF_RT"."SALES_REQUEST"."DV_SALES_ACCOUNT"
JOIN "SURF_RT"."SALES_CONTRACT" on "SURF_RT"."SALES_CONTRACT"."DV_ACCOUNT" = "SURF_RT"."SALES_REQUEST"."DV_SALES_ACCOUNT"
I am getting an error no matter what I try and it has to be because of the partition. Does anyone know the solution here?
I suspect that you just need to alias the derived table so you can then refer to join it. In many databases this is mandatory anyway, but apparently not in Hana (otherwise your original query would not run).
But to join on a derived table (the resultset that is generated by the subquery), alias do help:
SELECT
...
FROM
(
select
*,
row_number() over ( partition by "DV_SALES_ACCOUNT" order by "U_ANALYZED_DATE" desc ) rownum
from "SURF_RT"."SALES_REQUEST"
) sr -- table alias
JOIN "SURF_RT"."SALES_ACCOUNT"
ON "SURF_RT"."SALES_ACCOUNT"."NAME" = "SURF_RT"."SALES_REQUEST"."DV_SALES_ACCOUNT"
JOIN "SURF_RT"."SALES_CONTRACT"
ON "SURF_RT"."SALES_CONTRACT"."DV_ACCOUNT" = sr."DV_SALES_ACCOUNT" --reference to the derived table
WHERE
...
Side notes:
you should use table aliases for other tables involved in the query too, in order to make the code more readable
you should also prefix each column in the query with the identifier of the table it belongs to, so the query is unambiguous (and easier to maintain)
The problem with this query is not "that the where rownum = 1 needs to be at the end" but that the OP got confused by the bracketing of SQL expression.
More specifically, trying to reference the sub-query data by specifying join conditions against the base table that is used in the sub-query:
JOIN "SURF_RT"."SALES_ACCOUNT"
on "SURF_RT"."SALES_ACCOUNT"."NAME" = "SURF_RT"."SALES_REQUEST"."DV_SALES_ACCOUNT"
JOIN "SURF_RT"."SALES_CONTRACT"
on "SURF_RT"."SALES_CONTRACT"."DV_ACCOUNT" = "SURF_RT"."SALES_REQUEST"."DV_SALES_ACCOUNT"
Since the sub-query (derived table) is used in the query and should be used for the join, it needs to be referred in the join condition, instead.
So, yes, it needs a table alias here and the join conditions need to refer to it.
SELECT
...
FROM
(select *
, row_number() over
(partition by "DV_SALES_ACCOUNT"
order by "U_ANALYZED_DATE" desc) rownum
from
"SURF_RT"."SALES_REQUEST") sr
INNER JOIN "SURF_RT"."SALES_ACCOUNT" sa
on sa."NAME" = sr."DV_SALES_ACCOUNT"
INNER JOIN "SURF_RT"."SALES_CONTRACT" sc
on sc."DV_ACCOUNT" = sr."DV_SALES_ACCOUNT"
WHERE
sr.rownum = 1
AND "DV_SALES_CATEGORY" = 'Compliance'
AND "DV_STATE" NOT IN ('Closed Canceled')
AND (YEAR("U_ANALYZED_DATE") = '2019'
AND MONTH("U_ANALYZED_DATE") IN ('10','11','12')
OR YEAR("U_ANALYZED_DATE") = '2020'
AND MONTH("U_ANALYZED_DATE") IN ('1','2','3'))
AND "U_USD_TOTAL_POTENTIAL_NNACV" > 0
ORDER BY
"U_ANALYZED_DATE" desc;
With just this little bit of standard SQL syntax and formatting of code the query got a lot easier to understand.
Now it's even obvious that the IN conditions for MONTH and YEAR should in fact be integers, not strings as these functions return integers.
SELECT
...
FROM
(SELECT *
, row_number() over
(partition by "DV_SALES_ACCOUNT"
order by "U_ANALYZED_DATE" desc) rownum
FROM
"SURF_RT"."SALES_REQUEST") sr
INNER JOIN "SURF_RT"."SALES_ACCOUNT" sa
on sa."NAME" = sr."DV_SALES_ACCOUNT"
INNER JOIN "SURF_RT"."SALES_CONTRACT" sc
on sc."DV_ACCOUNT" = sr."DV_SALES_ACCOUNT"
WHERE
sr.rownum = 1
AND "DV_SALES_CATEGORY" = 'Compliance'
AND "DV_STATE" NOT IN ('Closed Canceled')
AND ( YEAR("U_ANALYZED_DATE") = 2019
AND MONTH("U_ANALYZED_DATE") IN (10, 11, 12)
OR YEAR("U_ANALYZED_DATE") = '2020'
AND MONTH("U_ANALYZED_DATE") IN (1 , 2 , 3 )
)
AND "U_USD_TOTAL_POTENTIAL_NNACV" > 0
ORDER BY
"U_ANALYZED_DATE" DESC

How to join 100 random rows from table 1 multiple other tables in oracle

I have scrapped my previous question as I did not do a good job explaining. Maybe this will be simpler.
I have the following query.
Select * from comp_eval_hdr, comp_eval_pi_xref, core_pi, comp_eval_dtl
where comp_eval_hdr.START_DATE between TO_DATE('01-JAN-16' , 'DD-MON-YY')
and TO_DATE('12-DEC-17' , 'DD-MON-YY')
and comp_eval_hdr.COMP_EVAL_ID = comp_eval_dtl.COMP_EVAL_ID
and comp_eval_hdr.COMP_EVAL_ID = comp_eval_pi_xref.COMP_EVAL_ID
and core_pi.PI_ID = comp_eval_pi_xref.PI_ID
and core_pi.PROGRAM_CODE = 'PS'
Now if I only want a random 100 rows from the comp_eval_hdr table to join with the other tables how would I go about it? If it makes it easier you can disregard the comp_eval_dtl table.
I think you are pretty much there. You just need subqueries, table aliases, and JOIN conditions:
SELECT . . .
FROM (SELECT a.*
FROM (SELECT a.*
FROM a
WHERE a.START_DATE BEWTWEEN DATE '2016-01-01' AND DATE '2017-12-12'
ORDER BY DBMS_RANDOM.VALUE
) a
WHERE ROWNUM <= 100
) a JOIN
mapping m
ON a.? = m.? JOIN
b
ON m.? = b.?;
The ? is just a placeholder for the join columns.
It's a bit of a stretch to know what you want with the question as written but here's my attempt.
WITH rand_list AS
(SELECT * FROM comp_eval_hdr
WHERE comp_eval_hdr.START_DATE BEWTWEEN TO_DATE('01-JAN-16' , 'DD-MON-YY') AND TO_DATE('12-DEC-17' , 'DD-MON-YY')
ORDER BY DBMS_RANDOM.VALUE)
first_100 AS
(SELECT *
FROM rand_list
WHERE ROWNUM <=100)
SELECT md.col_1, t3.col_a
FROM first_100 md
INNER JOIN
table2 t2 ON md.id_column = t2.fk_comp_eval_hdr_id
INNER JOIN
table3 t3 ON t3.id_column = t2.fk_table3_id
You haven't given any indication how they join or the table names and obviously I haven't run this against any mock tables.
You've got a list of randomised records with RAND_LIST which you could, if you wanted, combine with the FIRST_100 query (your choice).
The main query then just joins that through your mapping table (T2) to your 'multiples' table (T3).
how does table 2 look like?...Let me put one example as person table and order table?
select * from (
select * from person ps , order order where ps.city = 'mumbai' and ps.id = order.purchasedby ) porder where porder.rownum <= 100
I did not tested it but it will look something like this.

Selecting ONLY Duplicates from a joined tables query

I have the following query that I'm trying to join two tables matching their ID so I can get the duplicated values in "c.code". I've tried a lot of queries but nothing works. I have a 500k rows in my database and with this query I only get 5k back, which is not right. Im positive it's at least 200K. I also tried to use Excel but it's too much for it to handle.
Any ideas?
Thanks in advance, everyone.
SELECT c.code, c.name as SCT_Name, t.name as SYNONYM_Name, count(c.code)
FROM database.Terms as t
join database.dbo.Concepts as c on c.ConceptId = t.ConceptId
where t.TermTypeCode = 'SYNONYM' and t.ConceptTypeCode = 'NAME_Code' and c.retired = '0'
Group by c.code, c.name, t.name
HAVING COUNT(c.code) > = 1
Order by c.code
with data as (
select c.code, c.name as SCT_Name, t.name as SYNONYM_Name
from database.Terms as t inner join database.dbo.Concepts as c
on c.ConceptId = t.ConceptId
where
t.TermTypeCode = 'SYNONYM'
and t.ConceptTypeCode = 'NAME_Code'
and c.retired = '0'
)
select *
--, (select count(*) from data as d2 where d2.code = data.code) as code_count
--, count(*) over (partition by code) as code_count
from data
where code in (select code from data group by code having count(*) > 1)
order by code
If you want just duplicates of c.code, your Group By is wrong (and so is your Having clause). Try this:
SELECT c.code
FROM database.Terms as t
join database.dbo.Concepts as c on c.ConceptId = t.ConceptId
where t.TermTypeCode = 'SYNONYM' and t.ConceptTypeCode = 'NAME_Code' and c.retired = '0'
Group by c.code
HAVING COUNT(c.code) > 1
This will return all rows where you have more than one c.code value.
You need to use INTERSECT instead of JOIN. Basically you perform the select on the first table then intersect with the second table. The result is the duplicate rows.
Only select the id column, though, otherwise the intersect won't work as expected.

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

MS-Access -> SELECT AS + ORDER BY = error

I'm trying to make a query to retrieve the region which got the most sales for sweet products. 'grupo_produto' is the product type, and 'regiao' is the region. So I got this query:
SELECT TOP 1 r.nm_regiao, (SELECT COUNT(*)
FROM Dw_Empresa
WHERE grupo_produto='1' AND
cod_regiao = d.cod_regiao) as total
FROM Dw_Empresa d
INNER JOIN tb_regiao r ON r.cod_regiao = d.cod_regiao ORDER BY total DESC
Then when i run the query, MS-Access asks for the "total" parameter. Why it doesn't consider the newly created 'column' I made in the select clause?
Thanks in advance!
Old Question I know, but it may help someone knowing than while you cant order by aliases, you can order by column index. For example, this will work without error :
SELECT
firstColumn,
IIF(secondColumn = '', thirdColumn, secondColumn) As yourAlias
FROM
yourTable
ORDER BY
2 ASC
The results would then be ordered by the values found in the second column wich is the Alias "yourAlias".
Aliases are only usable in the query output. You can't use them in other parts of the query. Unfortunately, you'll have to copy and paste the entire subquery to make it work.
You can do it like this
select * from(
select a + b as c, * from table)
order by c
Access has some differences compared to Sql Server.
Why it doesn't consider the newly
created 'column' I made in the select
clause?
Because Access (ACE/Jet) is not compliant with the SQL-92 Standard.
Consider this example, which is valid SQL-92:
SELECT a AS x, c - b AS y
FROM MyTable
ORDER
BY x, y;
In fact, x and y the only valid elements in the ORDER BY clause because all others are out of scope (ordinal numbers of columns in the SELECT clause are valid though their use id deprecated).
However, Access chokes on the above syntax. The equivalent Access syntax is this:
SELECT a AS x, c - b AS y
FROM MyTable
ORDER
BY a, c - b;
However, I understand from #Remou's comments that a subquery in the ORDER BY clause is invalid in Access.
Try using a subquery and order the results in an outer query.
SELECT TOP 1 * FROM
(
SELECT
r.nm_regiao,
(SELECT COUNT(*)
FROM Dw_Empresa
WHERE grupo_produto='1' AND cod_regiao = d.cod_regiao) as total
FROM Dw_Empresa d
INNER JOIN tb_regiao r ON r.cod_regiao = d.cod_regiao
) T1
ORDER BY total DESC
(Not tested.)
How about:
SELECT TOP 1 r.nm_regiao
FROM (SELECT Dw_Empresa.cod_regiao,
Count(Dw_Empresa.cod_regiao) AS CountOfcod_regiao
FROM Dw_Empresa
WHERE Dw_Empresa.[grupo_produto]='1'
GROUP BY Dw_Empresa.cod_regiao
ORDER BY Count(Dw_Empresa.cod_regiao) DESC) d
INNER JOIN tb_regiao AS r
ON d.cod_regiao = r.cod_regiao
I suggest using an intermediate query.
SELECT r.nm_regiao, d.grupo_produto, COUNT(*) AS total
FROM Dw_Empresa d INNER JOIN tb_regiao r ON r.cod_regiao = d.cod_regiao
GROUP BY r.nm_regiao, d.grupo_produto;
If you call that GroupTotalsByRegion, you can then do:
SELECT TOP 1 nm_regiao, total FROM GroupTotalsByRegion
WHERE grupo_produto = '1' ORDER BY total DESC
You may think it's extra work to create the intermediate query (and, in a sense, it is), but you will also find that many of your other queries will be based off of GroupTotalsByRegion. You want to avoid repeating that logic in many other queries. By keeping it in one view, you provide a simplified route to answering many other questions.
How about use:
WITH xx AS
(
SELECT TOP 1 r.nm_regiao, (SELECT COUNT(*)
FROM Dw_Empresa
WHERE grupo_produto='1' AND
cod_regiao = d.cod_regiao) as total
FROM Dw_Empresa d
INNER JOIN tb_regiao r ON r.cod_regiao = d.cod_regiao
) SELECT * FROM xx ORDER BY total