How can I alter this to run in postgresql? - sql

What needs changing for this to run in postgreSQL?
I was given the piece of sql
UPDATE ACC
SET ACC.ACC_EC = SITESmin.ACC_EC,
ACC.ACC_NC = SITESmin.ACC_NC
FROM ACC
INNER JOIN LATERAL ( SELECT TOP 1
*
FROM SITES
ORDER BY ( acc_ec - site_etg ) * ( acc_ec - site_etg ) + (acc_ncb - site_ntg ) * ( acc_ncb - site_ntg )
) SITESmin;
It seems to be using SET but I do not know why, so if it's not needed drop it.
I am trying to get postgresql to work out distances. For every record in file one I have to compare to 3300 records in file 2 and select the nearest. Received wisdom suggests an array solution for the 3300 but I do not know how to do that. Perhaps it it a "sub query" in SQL.
If I am permitted to upload samples I will do so, though I have the feeling this is not allowed?
Here are the filed names
public.acc.Location_Easting_OSGR
public.acc.Location_Northing_OSGR
"public"."Sites"."SITE_ETG"
"public"."Sites"."SITE_NTG"

Try this:
WITH SITESmin as (
SELECT ACC_EC, ACC_NC
FROM SITES
ORDER BY ( acc_ec - site_etg ) * ( acc_ec - site_etg ) + (acc_ncb - site_ntg ) * ( acc_ncb - site_ntg )
LIMIT 1
)
UPDATE ACC
SET ACC.ACC_EC = SITESmin.ACC_EC,
ACC.ACC_NC = SITESmin.ACC_EC
FROM SITESmin;
If it does not work, please provide the schema and some data to make it easier to reproduce

Related

Count in the SUM SQL

I have the sql function like the following:
SELECT
SUM(3 * tb_spp.bulanan_spp ),
COUNT(tb_bulan.id) AS JUMLAH,
SUM( count(tb_bulan.id) * tb_angsuran_spp.nominal_spp ),
SUM( (3 * tb_spp.bulanan_spp) - (3 * tb_angsuran_spp.nominal_spp) ) as SPP
FROM tb_spp, tb_angsuran_spp, tb_bulan
where tb_spp.id_siswa = tb_angsuran_spp.id_siswa and tb_spp.id_siswa = '1'
and tb_bulan.id = tb_angsuran_spp.id_bulan
and tb_bulan.id between '1' and '2'
But when i run the error message appears '# 1111 - Invalid use of group function'
What is the cause and how is the solution?
sum(count()) isn't generally allowed. There are a few other changes I would make to the query as well:
SELECT SUM( 3 * s.bulanan_spp ),
count(b.id) as JUMLAH,
SUM(a.nominal_spp ),
SUM( (3 * s.bulanan_spp) - (3 * a.nominal_spp) ) as SPP
FROM tb_spp s JOIN
tb_angsuran_spp a
on s.id_siswa = a.id_siswa join
tb_bulan b
on b.id = a.id_bulan
where s.id_siswa = 1 and
b.id between 1 and 2;
Notes:
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Table aliases make the query easier to write and to read.
Ids are usually numbers; hence I removed the single quotes (they are appropriate for strings).
I'm not sure that your sums and counts will produce correct answers. If not, ask another question, including sample data and desired results. This answer addresses the syntax problems in this question.

SQL Server : spatial query result are not showing

SELECT Distinct lu.ObjectID
FROM LAND_USE_EVW as lu
WHERE NOT EXISTS (SELECT LAND_USE_EVW.OBJECTID
FROM LAND_USE_EVW, MUNICIPALITIES_EVW
WHERE LAND_USE_EVW.Shape.STCentroid().STIntersects(MUNICIPALITIES_EVW.shape) = 1
)
I was trying to get a result that opposite of below
select LAND_USE_EVW.OBJECTID
from LAND_USE_EVW, MUNICIPALITIES_EVW
where LAND_USE_EVW.Shape.STCentroid().STIntersects(MUNICIPALITIES_EVW.shape) = 1
= 0 didn't work therefore I'm trying to come up with other idea.
But result shows nothing. No errors or warning.
found answer
WHERE NOT EXISTS (SELECT LAND_USE_EVW.OBJECTID
FROM LAND_USE_EVW, MUNICIPALITIES_EVW
removing LAND_USE_EVW from FROM LAND_USE_EVW solve the problem

Database (Oracle 11g) query optimization for joins

So I am trying to optimize a bunch of queries which are taking a lot of time. What I am trying to figure out is how to create an index on columns from different tables.
Here is a simple version of my problem.
What I did
After Googling I looked into bitmap index but I am not sure if this is the right way to solve the issue
Issue
There is a many to many relationship b/w Student(sid,...) and Report(rid, year, isdeleted)
StudentReport(id, sid, rid) is the join table
Query
Select *
from Report
inner join StudentReport on Report.rid = StudentReport.rid
where Report.isdeleted = 0 and StudentReport.sid = x and Report.year = y
What is the best way to create an index?
Please try this:
with TMP_REP AS (
Select * from Report where Report.isdeleted = 0 AND Report.year = y
)
,TMP_ST_REP AS(
Select *
from StudentReport where StudentReport.sid = x
)
SELECT * FROM TMP_REP R, TMP_ST_REP S WHERE S.rid = R.rid

how to optimize several "WHERE (Select .... ) = value" from same table

It's hard to compose a topic name for me. But I can show an example :
WHERE (SELECT [ID_Line] FROM [Event] WHERE [Event].[Name] = [A].[Col]) = 2
AND (SELECT [DataType] FROM [Event] WHERE [Event].[Name] = [A].[Col]) = 2
Here I'm processing 2 queries when I really need something like that :
WHERE (SELECT [ID_Line],[DataType] FROM [Event] WHERE [Event].[Name] = [A].[Col]) = 2,2
but SQL doesn't work with tuples, so must I make Inner Join here ?
you can try something like this :
WHERE EXISTS (
SELECT [ID_Line] FROM [Event] WHERE
[Event].[Name] = [A].[Col] AND
[Event].[ID_Line] = 2 AND
[Event].[DataType] = 2
)
If you provide more information about the complete query and your database structure, a more precise answer could be given. It is possible that this isn't the best solution.
You can try to melt the fields using a melting operator. In ORACLE PL/SQL you use || (double pipe), for example.

Selecting elements that don't exist

I am working on an application that has to assign numeric codes to elements. This codes are not consecutives and my idea is not to insert them in the data base until have the related element, but i would like to find, in a sql matter, the not assigned codes and i dont know how to do it.
Any ideas?
Thanks!!!
Edit 1
The table can be so simple:
code | element
-----------------
3 | three
7 | seven
2 | two
And I would like something like this: 1, 4, 5, 6. Without any other table.
Edit 2
Thanks for the feedback, your answers have been very helpful.
This will return NULL if a code is not assigned:
SELECT assigned_codes.code
FROM codes
LEFT JOIN
assigned_codes
ON assigned_codes.code = codes.code
WHERE codes.code = #code
This will return all non-assigned codes:
SELECT codes.code
FROM codes
LEFT JOIN
assigned_codes
ON assigned_codes.code = codes.code
WHERE assigned_codes.code IS NULL
There is no pure SQL way to do exactly the thing you want.
In Oracle, you can do the following:
SELECT lvl
FROM (
SELECT level AS lvl
FROM dual
CONNECT BY
level <=
(
SELECT MAX(code)
FROM elements
)
)
LEFT OUTER JOIN
elements
ON code = lvl
WHERE code IS NULL
In PostgreSQL, you can do the following:
SELECT lvl
FROM generate_series(
1,
(
SELECT MAX(code)
FROM elements
)) lvl
LEFT OUTER JOIN
elements
ON code = lvl
WHERE code IS NULL
Contrary to the assertion that this cannot be done using pure SQL, here is a counter example showing how it can be done. (Note that I didn't say it was easy - it is, however, possible.) Assume the table's name is value_list with columns code and value as shown in the edits (why does everyone forget to include the table name in the question?):
SELECT b.bottom, t.top
FROM (SELECT l1.code - 1 AS top
FROM value_list l1
WHERE NOT EXISTS (SELECT * FROM value_list l2
WHERE l2.code = l1.code - 1)) AS t,
(SELECT l1.code + 1 AS bottom
FROM value_list l1
WHERE NOT EXISTS (SELECT * FROM value_list l2
WHERE l2.code = l1.code + 1)) AS b
WHERE b.bottom <= t.top
AND NOT EXISTS (SELECT * FROM value_list l2
WHERE l2.code >= b.bottom AND l2.code <= t.top);
The two parallel queries in the from clause generate values that are respectively at the top and bottom of a gap in the range of values in the table. The cross-product of these two lists is then restricted so that the bottom is not greater than the top, and such that there is no value in the original list in between the bottom and top.
On the sample data, this produces the range 4-6. When I added an extra row (9, 'nine'), it also generated the range 8-8. Clearly, you also have two other possible ranges for a suitable definition of 'infinity':
-infinity .. MIN(code)-1
MAX(code)+1 .. +infinity
Note that:
If you are using this routinely, there will generally not be many gaps in your lists.
Gaps can only appear when you delete rows from the table (or you ignore the ranges returned by this query or its relatives when inserting data).
It is usually a bad idea to reuse identifiers, so in fact this effort is probably misguided.
However, if you want to do it, here is one way to do so.
This the same idea which Quassnoi has published.
I just linked all ideas together in T-SQL like code.
DECLARE
series #table(n int)
DECLARE
max_n int,
i int
SET i = 1
-- max value in elements table
SELECT
max_n = (SELECT MAX(code) FROM elements)
-- fill #series table with numbers from 1 to n
WHILE i < max_n BEGIN
INSERT INTO #series (n) VALUES (i)
SET i = i + 1
END
-- unassigned codes -- these without pair in elements table
SELECT
n
FROM
#series AS series
LEFT JOIN
elements
ON
elements.code = series.n
WHERE
elements.code IS NULL
EDIT:
This is, of course, not ideal solution. If you have a lot of elements or check for non-existing code often this could cause performance issues.