UPDATE with nested query in PostgreSQL with unwanted results - mysql

Due to its geographic capabilities I'm migrating my database from MySQL to PostgreSQL/PostGIS, and SQL that used to be so trivial is now are becoming painfully slow to overcome.
In this case I use a nested query to obtain the results in two columns, having in 1st column an ID and in the 2nd a counting result and insert those results in table1.
EDIT: This is the original MySQL working code that I need to be working in PostgreSQL:
UPDATE table1 INNER JOIN (
SELECT id COUNT(*) AS cnt
FROM table2
GROUP BY id
) AS c ON c.id = table1.id
SET table1.cnt = c.cnt
The result is having all rows with the same counting result, that being the 1st counting result of the nested select.
In MySQL this would be solved easily.
How would this work in PostgreSQL?
Thank you!

UPDATE table1 dst
SET cnt = src.cnt
FROM (SELECT id, COUNT (*) AS cnt
FROM table2
GROUP BY id) as src
WHERE src.id = dst.id
;

Related

Create a new variable in SQL by groupby

I have 2 sql table as follows:
First table t1:
Second table t2:
I need to calculate the count of "Number" column based on "Name" column from t1 and merge it with t2.
I wrote following code. But it seems not working
select *
from (
select Name, count(Number) as count
from t1
group by Name ) as a
join ( select *
from t2 ) as b
on a.Name = b.Name;
Can any one figure out what is wrong ? Thank you very much
I think you want to use SUM() instead of COUNT().
Because SUM() sums some integers, while COUNT() counts number of occurencies.
And as also stated in the comments, multiple columns with same names will create conflicts, so you have to select the wanted columns explicit (that is usually a good idea anyway).
You could obtain your wanted endgoal by this query:
select
SUM(Number),
t1.Name,
(select val1 FROM t2 WHERE t2.Name = t1.Name LIMIT 1) as val1
FROM t1
GROUP BY t1.Name
Example in sqlfiddle: http://sqlfiddle.com/#!9/04dddf/7

mysql subquery row comparision logic

I have question on the subquery logic. For my understanding, sql always parse the subquery and then outler query. However, the example from official documents does not support that.
linke as blow from mysql official documents
https://dev.mysql.com/doc/refman/8.0/en/subqueries.html
Here is another example, which again is impossible with a join
because it involves aggregating for one of the tables.
It finds all rows in table t1 containing a value that occurs twice in a given column:
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
For my understanding, when sql parse the subquery, it will find the
(SELECT COUNT(*) FROM t1 WHERE t1.id = t.id)
return scalar based on the table. then when it compare with 2
it will either return all row in t1 or nothing since it is easy true or false question.
obvious it does not like what office documents discussion
. based on the official documents, it is more like checking row by row from t1 table, make comparsion with scalar 2 and keep looping the whole table until the end.
why the logic is like? I have some difficulty to understand the logic.
Any future explaination will helps.
There is no difficulty.
It depends all how many rows you get back, because it will check every row of t1 and compare if the table has 2 row with that value. lieke you can see here https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=d70942c0321f9310c3b89dbc9435b418
(SELECT COUNT(*) FROM t1 WHERE t1.id = t.id)
reruns 1 value (1 column 1 row) for example 3 which it compares to your 2 with =
As long as the subquery only returns 1 Value you can compare it with a singular value with =
For multiple Rows in the result set you need IN
LIKE
SELECT * FROM t1 AS t
WHERE cis IN (SELECT t1.id FROM t1 WHERE t1.id = t.id);
And of course you can compare to multiple columns(also here you need ÌN if you have multiple rows)
SELECT * FROM t1 AS t
WHERE (2,2) = (SELECT COUNT(*),SUM(abc = 'test') FROM t1 WHERE t1.id = t.id);

MySQL: Fetching non-null values using multiple joins

I am running a few queries which I want to convert to a single query using joins
My first query is
1) SELECT * FROM ACT_TABLE1 where node='5bbcdded' order by Instance_ID desc;
The output of the above query is as below
ID Instance_ID NODE
2326600581 23266005612 5bbcdded1
2326524592 23265245712 5bbcdded2
2326523503 23265234213 5bbcdded3
2326523004 23265229614 5bbcdded4
2) Now, I grab topmost Instance_ID and run another select query as follows
SELECT * FROM ACT_TABLE2 where TOP_INST_ID = '23266005612';
Here, there might be a situation where select query returns a null value from above query. In that case, I grab second topmost Instance_ID and run same select query as follows
SELECT * FROM ACT_TABLE2 where TOP_INST_ID = '23265245712';
The output of the above query returns only single row as below
ID NEXT_ID TOP_INSTANCE_ID
232660056 232660056 232652457
3) Now, I grab topmost NEXT_ID and run another select query as follows
SELECT * FROM ACT_TABLE3 where NEXT_ID = '232660056';
The output of the above query returns only single row as below
ID EXEP_ID NEXT_ID
232660072 232660139 232660056
4) Now, I grab topmost EXEP_ID and run another select query as follows
SELECT field2 FROM ACT_TABLE4 where ID = '232660139';
The output of the above query returns field2 which is my final result
In other words, I want to pass node='5bbcdded' in my first table so that i can fetch value of field2 from my fourth table
You can do Inner Join between all the tables, using their relationships.
Then, employ multiple level Order By clauses starting from the first table (all in Descending order, since you want topmost from all the tables). We use LIMIT 1 to get the first row after sorting, which will be topmost.
Inner Join will ensure that any non-matching rows (null in the next table) will be ignored.
Try:
SELECT t4.field2
FROM ACT_TABLE1 AS t1
INNER JOIN ACT_TABLE2 AS t2 ON t2.TOP_INST_ID = t1.Instance_ID
INNER JOIN ACT_TABLE3 AS t3 ON t3.NEXT_ID = t2.NEXT_ID
INNER JOIN ACT_TABLE4 AS t4 ON t4.ID = t3.EXEP_ID
where t1.node = '5bbcdded'
ORDER BY t1.Instance_ID DESC, t2.NEXT_ID DESC, t3.EXEP_ID DESC
LIMIT 1

Get Column From Subquery

I currently have the following (simplified) sql which selects user data from a main table table1. This query only select users who have not logged in since a given date. I use a sub query as the login table is separate from the main table. The two tables relate via a user ID column. This works perfectly.
// sql to get all records that haven't logged in since date above
$sql = "SELECT t1.*
FROM table1 t1
WHERE '2016-08-01' > (SELECT MAX(t2.DateCol)
FROM table2 t2
WHERE t2.userId= t1.userId)";
My question is, is there a way of returning the value of MAX(t2.DateCol)?
I tired this but is didn't reconise the column
$sql = "SELECT t1.*, MAX(t2.DateCol) ....
FYI: This sql is parsed into a custom PDO function so no need to warn about insecurities of mysql functions.
A quick solution (not knowing your skillset or data setup) - Move the sub-query in scope.
$sql = "SELECT t1.*,
(SELECT MAX(t2.DateCol)
FROM table2 t2
WHERE t2.userId= t1.userId) AS LastLogin
FROM table1 t1
HAVING '2016-08-01' > LastLogin ";
You will need to use HAVING instead of WHERE because you are comparing using an alias. If your query cannot use HAVING due to other factors then you'll need to repeat the subquery (not ideal).
If you want to show the aggregation result, you should select from the aggregation. In order to do so group your aggregation by userid. You can use HAVING to only select desired ones.
select t1.*, t2.max_datecol
from table1 t1
join
(
select userid, max(datecol) as max_datecol
from table2
group by userid
having max(datecol) < date '2016-08-01'
) t2 on t2.userid = t1.userid;

How do I perform SQL Join equivalent functionality in sphinx?

Can anyone tell me how can we achieve the functionality of SQL join in sphinx search?
I want to index few columns from table1 and few from table2.
Tables are in MySQL.
1° as Barryhunter answer
sql_query = SELECT t1.id,t1...., t2.... FROM table1 AS t1 INNER JOIN table2 AS t2 ON ....
2° if one-to-many
sql_query = SELECT t1.id,t1...., group_concat(t2.foo) ASt 2_foo, . FROM table1 AS t1 INNER JOIN table2 AS t2 ON .... GROUP BY t1.id
group_concat has length limitation but sphinx is marvellous
sql_query = SELECT t1.id,t1....,. FROM table1 AS t1;
sql_joined_field = t2_foo from query;\
SELECT t2.rel_t1_id , t2.foo\
FROM table2` AS t2\
ORDER by t2.rel_t1_id ASC
As my English is poor, read this is probably more clear
http://sphinxsearch.com/docs/current/conf-sql-joined-field.html
sql_joined_field = t2_foo would add one more "searchable" field called t2_foo. In this field you retrieve t2.foo content (like the group concat but seperated by space)
The first column must be the id matching to t1.id in your sql_query
ORDER by theID ASC is mandatory
In same idea you can use mva for multiple value in an attribute
http://sphinxsearch.com/docs/current/conf-sql-attr-multi.html
sql_attr_multi = uint tag from query; \
SELECT id, tag FROM tags
You can just use a join in the sql_query, its just a standard MySQL query, that indexer runs and indexes the output. the MySQL server just needs to run it.
sql_query = SELECT id,t.name,o.test FROM table1 t INNER JOIN other o USING (id)