Converting MS Access Queries to PostgreSQL queries (format()) - sql

I have a query from MS Access SQL that I would like to execute in PostgreSQL:
SELECT Format("start_date", 'mmmm') AS "Month",
DFS_FIRE_ARCHIVE.FIRE_YEAR AS "Year",
Count(DFS_FIRE_ARCHIVE.FIRE_ZONE) AS "Number of Fires",
OBJECTIVES_NFD."response_category"
FROM (DFS_FIRE_ARCHIVE
INNER JOIN OBJECTIVE_ORDER ON DFS_FIRE_ARCHIVE.OBJECTIVE = OBJECTIVE_ORDER.OBJECTIVE)
INNER JOIN OBJECTIVES_NFD ON OBJECTIVE_ORDER.OBJECTIVE = OBJECTIVES_NFD.OBJECTIVE
GROUP BY Format("start_date",'mmmm'),
DFS_FIRE_ARCHIVE.FIRE_YEAR,
DFS_FIRE_ARCHIVE.OBJECTIVE,
Format("start_date",'mm'),
OBJECTIVE_ORDER.ORDER,
DFS_FIRE_ARCHIVE.FIRE_MGT_ZONE,
DFS_FIRE_ARCHIVE.FIRE_TYPE,
OBJECTIVES_NFD."response_category"
HAVING (((DFS_FIRE_ARCHIVE.FIRE_YEAR)=2009) AND ((DFS_FIRE_ARCHIVE.FIRE_MGT_ZONE)='INT') AND ((DFS_FIRE_ARCHIVE.FIRE_TYPE)='IFR'))
ORDER BY Format("start_date",'mm'), OBJECTIVE_ORDER.ORDER, DFS_FIRE_ARCHIVE.OBJECTIVE;
The error I am receiving is:
ERROR: function format(timestamp without time zone, unknown) does not exist
LINE 1: SELECT Format("start_date", 'mmmm') AS "Month",
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Any help would be appreciated, thank-you.

The function you should replace Format with is probably to_char, e.g. to_char(timestamp, 'MM').
Take a look at PostgreSQL documentation:
http://www.postgresql.org/docs/9.0/static/functions-formatting.html

You are looking for to_char():
http://www.postgresql.org/docs/current/static/functions-formatting.html

Related

Ambigously defined column in a subquery

I've the following subquery in an sql query:
(
SELECT ID_PLAN, ID_CURSO, NEDICION, NOMBRE AS NOMBREUNIDAD FROM ASISTEN, ALUMNOS, UNIDADES
WHERE ASISTEN.COD = ALUMNOS.COD AND UNIDADES.IDESTRUCTURA = ALUMNOS.IDESTRUCTURA
AND UNIDADES.CDUNDORG = ALUMNOS.CDUNDORG
AND UPPER(TRANSLATE(UNIDADES.NOMBRE, 'áéíóúÁÉÍÓÚ', 'aeiouAEIOU')) LIKE '%CONSEJERIA%'
GROUP BY ID_PLAN, ID_CURSO, NEDICION) ASIS
Problem I have I believe lies in that both table ALUMNOS and UNIDADES have a column named 'NOMBRE' so if I attempt to execute the query I obtain:
00000 - "column ambiguously defined"
To avoid that I thought about changing NOMBRE AS NOMBREUNIDAD to:
UNIDADES.NOMBRE AS NOMBREUNIDAD
But if I do that I get a:
00000 - "not a GROUP BY expression"
So, I don't know what to do so that subquery executes properly.
What should I change to properly execute query without changing the column name?
Aliases are pretty useful, if you use them. The simplify queries and make them easier to read and maintain. I'd suggest you to do so, as it'll also help query to work because Oracle doesn't know which table you actually meant when you selected those 4 columns - which tables do they belong to?
This is just a guess as I don't know your tables so you'll have to fix it yourself. Also, I literally JOINed tables; try to avoid comma-separating them in FROM clause and doing join in WHERE clause as it is supposed to filter data.
GROUP BY, as already commented, is probably useless. If you wanted to fetch distinct set of values, then use appropriate keyword: distinct.
SELECT DISTINCT n.id_plan,
s.id_curso,
u.nedicion,
u.nombre
FROM asisten n
JOIN alumnos s ON n.cod = s.cod
JOIN unidades u
ON u.idestructura = s.idestructura
AND u.cdundorg = s.cdundorg
WHERE UPPER (TRANSLATE (u.nombre, 'áéíóúÁÉÍÓÚ', 'aeiouAEIOU')) LIKE '%CONSEJERIA%'
I managed to solve my problem:
(
SELECT ID_PLAN, ID_CURSO, NEDICION, UNIDADES.NOMBRE AS NOMBREUNIDAD
FROM ASISTEN, ALUMNOS, UNIDADES
WHERE ASISTEN.COD = ALUMNOS.COD AND UNIDADES.IDESTRUCTURA = ALUMNOS.IDESTRUCTURA
AND UNIDADES.CDUNDORG = ALUMNOS.CDUNDORG
AND UPPER(TRANSLATE(UNIDADES.NOMBRE, 'áéíóúÁÉÍÓÚ', 'aeiouAEIOU')) LIKE '%CONSEJERIA%'
GROUP BY UNIDADES.NOMBRE,ID_PLAN, ID_CURSO, NEDICION
)

How to create a new column using existing column in SQL Redshift

I am trying to create a new column in SQL with certain conditions in DBVisualizer by connecting redshift data source.
I used the following command to achieve the results but getting syntax error.
I would be really grateful for any help.
Code:
select existing_col, if(existing_col like '%LM%','LM',if(referrer like
'%LH%','LH',if(existing_col like '%HT%','HT',if(existing_col like '%M_App%','LM','Other
Business Lines'))))
AS derived_variable from
db.table_name;
Error:
[Code: 0, SQL State: 42883] ERROR: function if(boolean, "unknown", "unknown") does not exist
Hint: No function matches the given name and argument types. You may need to add explicit type casts.
select existing_col,
if(existing_col like '%LM%','LM',if(existing_col like '%LH%','LH',if(existing_col like '%HT%','HT',if(existing_col like '%Mint_App%','LM','Other Business Lines'))))
AS derived_variable from
db.table_name
Expected Output:
existing_col derived_variable
PB Other
OTT Other
Mint_App LM
LSLM LM
LMG LM
HTTC HT
KLH LH
Thanks.
As stated in the error message, the IF() function does not exist in Redshift. Therefore, you should use CASE:
select
existing_col,
case
when existing_col like '%LM%' or existing_col like '%Mint_App%' then 'LM'
when existing_col like '%LH%' then 'LH'
when existing_col like '%HT%' then 'HT'
else 'Other'
end as derived_variable
from db.table_name

Raw query doesn't accept where condition with date

I have this Raw query, but when I run it I get a sql syntax error.
here is the date params i use :
$last_week = Carbon::now()->subdays(7);
$last_2_week = Carbon::now()->subdays(14);
here is the query:
DB::raw("(SELECT SUM(vd.qty_available) FROM products AS P
JOIN variations AS V ON V.product_id=P.id
JOIN variation_location_details AS VD ON VD.variation_id=V.id
JOIN transaction_sell_lines as ts ON ts.variation_id=v.id
JOIN transactions as t ON ts.transaction_id=t.id
WHERE t.transaction_date>=$last_2_week) AS last_2_week_quantity"),
error :SQLSTATE[42000]: Syntax error or access violation: 1064
The actual SQL output will be similar to WHERE t.transaction_date >= 2020-01-01 00:00:00
which is invalid, you should wrap it in a single quotes.
something like
WHERE t.transaction_date>= '{$last_2_week}'
or better
WHERE t.transaction_date>= '{$last_2_week->toDateTimeString()}'
The toDateTimeString() forces the output to be in the correct format in this case.
or even better use the parameter binding
->whereRaw("... t.transaction_date>= ?", [$last_2_week->toDateTimeString()])
Put some space between the operand.
Instead of:
WHERE t.transaction_date>=$last_2_week) AS last_2_week_quantity")
Put:
WHERE t.transaction_date >= $last_2_week) AS last_2_week_quantity")

Assistance with Access ADP and/or SQL iif statement

I'm using Access ADP as a front end to SQL. I have two tables:
One is Price_2018
One is Price_2020
I want to choose Price from the Price_2018 or the Price_2020 table, depending upon the Purchase_Date. I tried first putting IiF statement in the Query Designer:
Iif ([Purchase_Date] < Convert(DateTime, '2020-01-01 00:00:00'),[Price_2018],[Price_2020])
Access didn't allow that and ended up putting the whole thing in quotes in the SQL pane, so all I got was text output.
Someone suggested putting in the Select section:
CASE ([Purchase_Date] < CONVERT(DATETIME, '2020-01-01 00:00:00') WHEN 1 THEN [Price_2018] ELSE [Price_2020]
That didn't work either and gave me this error:
Error in list of function arguments: '<' not recognized.Error in list of function arguments: ',' not recognized.Error in list of function arguments: 'FROM' not recognized.
Unable to parse query text.
How to resolve this error. I'm not familiar with using a CASE statement in Access or SQL.
I combined 2 Price tables (combined table called VWC_2018_2020) as suggested. Full query:
SELECT TOP 100 PERCENT dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_ID, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_Date_From, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Update_Status, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Account_Number, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_Units, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Modifiers, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Procedure_Code, NormalUnionCPASumAdjustments.SumAmount AS Adjustment, NormalUnionCPASumPayments.SumAmount AS Payment, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_Fee AS Charge, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_Fee - ISNULL(NormalUnionCPASumPayments.SumAmount, 0) AS Unpaid, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Primary_Diagnosis_Code, LastInsurancePmt.last_insurance_pmt, dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Patient_Number, dbo.VWCFees_2018_2020.VWC_2020, dbo.VWCFees_2018_2020.VWC_2018, IIF (dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_Date_From < CDate('2020-01-01 00:00:00'),dbo.VWCFees_2018_2020.VWC_2018,dbo.VWCFees_2018_2020.VWC_2020) AS VWCFEE
FROM dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo LEFT OUTER JOIN dbo.VWCFees_2018_2020 ON dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Procedure_Code = dbo.VWCFees_2018_2020.CPT LEFT OUTER JOIN dbo.NormalUnionCPASumAdjustments() NormalUnionCPASumAdjustments ON dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_ID = NormalUnionCPASumAdjustments.Service_ID LEFT OUTER JOIN dbo.NormalUnionCPASumPayments() NormalUnionCPASumPayments ON dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_ID = NormalUnionCPASumPayments.Service_ID LEFT OUTER JOIN dbo.LastInsurancePmt() LastInsurancePmt ON dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_ID = LastInsurancePmt.Service_ID
WHERE (dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Update_Status <= 1) AND (dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Service_Date_From BETWEEN #StartDate AND #EndDate) AND (dbo.VHCSERVER_Ntier_VHC_dbo_vwGenSvcInfo.Patient_Number = #VHC_NumberChild)
Running in Access, gives error message: '<' not recognized. Missing FROM clause. Unable to parse query text.
What now? Thanks
Since ADP files use an SQL Server backend (no longer supported as of MS Access 2013), you must use its TSQL dialect which does support IIF (or CASE) and can compare dates with string representations without conversion.
Below I extend to fuller query assuming various columns. Adjust as needed:
SELECT
...
IIF(t.[Purchase_Date] < '2020-01-01', p18.price, p20.price)
...
FROM [Transactions] t
INNER JOIN [Price_2018] p18
ON t.price_id = p18.price_id
INNER JOIN [Price_2020] p20
ON t.price_id = p20.price_id

PostgreSQL asking for 'group by' clause in where, when sending parameters

I have a simple query in PostgreSQL which is ok when I run it without any query parameters :
select date_trunc('week', action_time),count(*) from event
group by date_trunc('week', action_time);
But if I try to send the 'week' as a parameter like this (in Java):
PreparedStatement statement = connection.prepareStatement
("select date_trunc(?, action_time),count(*) from event"
+ " group by date_trunc(?, action_time)");
statement.setString(1,"week");
statement.setString(2,"week");
statement.execute();
it'll throw the following error:
ERROR: column "event.action_time" must appear in the GROUP BY clause or
be used in an aggregate function
is this normal behavior ?
When the query is prepared there's no guarantee that you will bind the same value ('week') for both placeholders. If you don't, the query would be illegal, and that's why postgres doesn't allow preparing it.
One way around this could be to change your query so you only bind 'week' once, and use it from inside a subquery:
PreparedStatement statement = connection.prepareStatement
("select dt, count(*) from (select date_trunc(?, action_time) as dt "
+ "from event) s group by dt");
statement.setString(1,"week");
statement.execute();
I think this should work, but Postgres can be a bit finicky. For instance, the following does not work:
select date_trunc(val, now())
from (select 'week' as val) t
But this does:
select date_trunc(val, now())
from (select cast('week' as text) as val) t
You might check if this version works:
select date_trunc(datepart, action_time), count(*)
from event cross join
(select cast(? as text) as datepart) vars
group by date_trunc(datepart, action_time);
And then supply only one parameter.
Like Mureinik mentioned its because postgres cant prove the statement arguments are the same.
I was able to use a column alias to provide the argument once.
eg
select date_trunc(?, action_time), count(*) from event
group by date_trunc(?, action_time);
becomes
select date_trunc(?, action_time) as action_t, count(*) from event
group by action_t;