How to access columns of subqueries with jooq? - mysql

i am having troubles understanding how to access columns from a subquery (MySQL). Here is my code:
Personne personne = Personne.PERSONNE.as("personne");
Evenement evenement = Evenement.EVENEMENT.as("evenement");
Genealogie genealogie = Genealogie.GENEALOGIE.as("genealogie");
Lieu lieu = Lieu.LIEU.as("lieu");
SelectField<?>[] select = { DSL.countDistinct(personne.ID).as("countRs"), lieu.LIBELLE.as("libelleRs"),
lieu.ID.as("idVille") };
Table<?> fromPersonne = evenement.innerJoin(personne).on(personne.ID.eq(evenement.IDPERS))
.innerJoin(genealogie).on(genealogie.ID.eq(personne.IDGEN)).innerJoin(lieu)
.on(lieu.ID.eq(evenement.IDLIEU));
Table<?> fromFamille = evenement.innerJoin(personne).on(personne.IDFAM.eq(evenement.IDFAM))
.innerJoin(genealogie).on(genealogie.ID.eq(personne.IDGEN)).innerJoin(lieu)
.on(lieu.ID.eq(evenement.IDLIEU));
GroupField[] groupBy = { lieu.ID };
Condition condition = //conditionally build, not relevant i think
result = create.select(DSL.asterisk())
.from(create.select(select).from(fromPersonne).where(condition).groupBy(groupBy)
.union(create.select(select).from(fromFamille).where(condition).groupBy(groupBy)))
// i would like something like this but i don't know how: .groupBy(groupBy).fetch();
Basicly what i have is:
SELECT
*
FROM(
(SELECT
countRs, libelleRs, idVille
FROM
fromPersonne
WHERE
-- conditions
GROUP BY lieu.ID)
UNION
(SELECT
countRs, libelleRs, idVille
FROM
fromFamille
WHERE
-- conditions
GROUP BY lieu.ID)
)GROUP BY lieu.ID -- this is where i need help
In a plain MySQL query i would just give an alias to the union and then make a reference to the column i want to group by using the alias but it seems like it does not work like this with JOOQ.
I just need to group the results of the subqueries together but i don't know how to make a reference to the subqueries columns... I am sure i would have to reference my subqueries in objects outside of that "main select" to be able to access the columns or something along those lines but i am lost in all the object types.

You have to assign your derived table to a local variable and dereference columns from it, e.g.
Table<?> t = table(
select(...).from(...).groupBy(...).unionAll(select(...).from(...).groupBy(...))
).as("t");
Field<Integer> tId = t.field(lieu.ID);

Related

SELECT statement inside a CASE statement in SNOWFLAKE

I have a query where i have "TEST"."TABLE" LEFT JOINED to PUBLIC."SchemaKey". Now in my final select statement i have a case statement where i check if c."Type" = 'FOREIGN' then i want to grab a value from another table but the table name value i am using in that select statement is coming from the left joined table column value. I've tried multiple ways to get to work but i keep getting an error, although if i hard code the table name it seems to work. i need the table name to come from c."FullParentTableName". Is what i am trying to achieve possible in snowflake and is there a way to make this work ? any help would be appreciated !
SELECT
c."ParentColumn",
c."FullParentTableName",
a."new_value",
a."column_name"
CASE WHEN c."Type" = 'FOREIGN' THEN (SELECT "Name" FROM TABLE(c."FullParentTableName") WHERE "Id" = 'SOME_ID') ELSE null END "TestColumn" -- Need assistance on this line...
FROM "TEST"."TABLE" a
LEFT JOIN (
select s."Type", s."ParentSchema", s."ParentTable", s."ParentColumn", concat(s."ParentSchema",'.','"',s."ParentTable",'"') "FullParentTableName",s."ChildSchema", s."ChildTable", trim(s."ChildColumn",'"') "ChildColumn"
from PUBLIC."SchemaKey" as s
where s."Type" = 'FOREIGN'
and s."ChildTable" = 'SOMETABLENAME'
and "ChildSchema" = 'SOMESCHEMANAME'
) c
on a."column_name" = c."ChildColumn"
Thanks !
In Snowflake you cannot dynamically use the partial results as tables.
You can use a single bound value via identifier to bind a value to table name
But you could write a Snowflake Scripting but it would need to explicitly join the N tables. Thus if you N is fixed, you should just join those.

NodeJS + MySQL, UPDATE with a JOIN, ambiguous column name

First of all, I understand why I'm getting this error message, and I know of a way to solve it, but I'm hoping for something more efficient than what I have in mind. Here is basically what I have:
UPDATE customer c
JOIN customer d ON c.customer_id = d.parent_customer_id
SET ?
WHERE d.customer_type = "Big Cheese";
So, the data being fed in to the "?" parameter looks like this:
{"customer_id": 10, "customer_name": "Cheese-It", ... }
The problem is, since I'm joining on a table that is basically itself, all of the columns have the same name. The only way I know how to fix this is edit the JSON and prefix all of the fields with the alias it needs:
{"c.customer_id": 10, "c.customer_name": "Cheese-It", ... }
I was hoping for a more elegant way of going about this. Is there a way to refactor my SQL so that it knows which table alias I want to update? Any ideas?
A subquery will do what you are wanting, but it's actually less efficient, as subqueries inside the WHERE clause are generally performance killers. I feel like you have to be parsing the JSON into SQL, so I would simply add the alias at that point.
Anyway, for reference, here's how you can refactor the SQL to not need an alias:
UPDATE customer
SET ?
WHERE customer_id IN (
SELECT c.customer_id
FROM customer c
JOIN customer d ON c.customer_id = d.parent_customer_id
WHERE d.customer_type = 'Big Cheese'
);
NOTE: this is untested
EDIT:
On second thought, an EXISTS clause would be slightly better for performance:
UPDATE customer c
SET ?
WHERE EXISTS (
SELECT 1
FROM customer d
WHERE d.parent_customer_id = c.customer_id
AND d.customer_type = 'Big Cheese'
);
Either way should work. As long as you don't have a JOIN in the update, there is only one table the SET columns can reference, so you will avoid the ambiguous column name error.
I know this is an older question, but I found a better solution that doesn't have the performance hit. You can add the alias to your property names in the object you're updating.
Here is the helper function to translate the standard property names with an alias.
const allowUpdate = ['name']
function addUpdateAlias(updated, alias) {
let validUpdate = {}
for (let p in updated) {
if (allowUpdate.indexOf(p) > -1) {
validUpdate[`${alias}.${p}`] = updated[p]
}
}
return validUpdate;
}
Now wrap the object you want to update with the function above and the alias is applied in the update!
Your parameters would then be: [addUpdateAlias(customer, 'c')] to pass into your original query.

JOIN on keys that don't have the same value

I am trying to do an INNER JOIN on two tables that have similar values, but not quite the same. One table has a fully qualified host name for its primary key, and the other the hosts short name, as well as the subdomain. It it safe to assume that the short name and the subdomain together are unique.
So I've tried:
SELECT table1.nisinfo.* FROM table1.nisinfo INNER JOIN table2.hosts ON (table1.nisinfo.shortname + '.' + table1.nisinfo.subdomainname + '.domain.com') = table2.hosts.fqhn WHERE table2.hosts.package = 'somepkg';
This doesn't return the results I expect, it returns the first result hundreds of times. I'd like to return distinct rows. It takes a long time to run as well.
What am I doing wrong? I was thinking of running a subquery to get the hostnames, but I don't know what the right path from here is.
Thank you!
You can use group by in your query so you can achieve the desired results you want
please see this two links
Group by with 2 distinct columns in SQL Server
http://www.sqlteam.com/article/how-to-use-group-by-with-distinct-aggregates-and-derived-tables
Try putting your results into a temp table and then view the table to make sure that the columns are as expected.
SELECT table1.nisinfo.*, table1.nisinfo.shortname + '.' + table1.nisinfo.subdomainname + '.domain.com' AS ColID
INTO #temp
FROM table1.nisinfo;
Select *
from #temp INNER JOIN table2.hosts ON ##temp.ColID = table2.hosts.fqhn
WHERE table2.hosts.package = 'somepkg'
;
Put a Group By clause at the end of the second statement
So in this case, I used a subquery to get the initial results, and then used a join.
SELECT table1.nisinfo.* FROM table1.nisinfo JOIN (SELECT distinct(fqhn) FROM table2.hosts WHERE package = 'bash') AS FQ ON ((SUBSTRING_INDEX(FQ.fqhn, '.', 1)) = table1.nisinfo.shortname);

Facing issue with SQL query in the where clause

I have the following database scheme on MySQL and I would like to retrieve all elements for a speciic id.
So for instance, I would like to retrieve cities, categories, departments linked to the coupon_id=1 (and other fields).
I wrote the following SQL query but unfortunatelly could not get the desired result.
SELECT cc_coupon.id_coupon as idCoupon,
cc_coupon.condition_coupon,
cc_coupon.description,
cc_coupon.type_coupon,
cc_coupon_by_categorie.id_categorie,
cc_categorie.categorie as category,
cc_annonceur.raison_sociale,
cc_coupon_active_in_cities.id_ville as ville_slug,
cc_villes_france.ville_slug,
cc_villes_france.ville_nom_departement,
cc_villes_france.ville_departement
FROM cc_coupon,
cc_coupon_by_categorie,
cc_categorie,
cc_annonceur,
cc_coupon_active_in_cities,
cc_coupon_active_in_departments,
cc_villes_france
WHERE cc_coupon.id_coupon = cc_coupon_by_categorie.id_coupon
and cc_categorie.id_categorie = cc_coupon_by_categorie.id_categorie
and cc_coupon.id_annonceur = cc_annonceur.id_annonceur
and cc_coupon.id_coupon = cc_coupon_active_in_cities.id_coupon
and cc_villes_france.id_ville = cc_coupon_active_in_cities.id_ville
and cc_villes_france.ville_departement = cc_coupon_active_in_departments.ville_departement
and cc_coupon.id_coupon = 1
and cc_coupon_active_in_cities.id_coupon = 1
and cc_coupon_active_in_departments.id_coupon = 1
Thanks for your help.
I think you should use the on and not where when you want to join two tables. When you want to specify other conditions use where clause.

MySql dynamic column name

[major edit to make things clear]
I want to write a query that returns a dynamic column name like this:
SELECT
f2 AS
(
SELECT column_name
FROM column_names_tbl
WHERE column_name = "experience"
limit 0,1
)
FROM some_table
so that would output the same as this:
SELECT
f2 AS experience
FROM some_table
This is no correct SQL syntax, even because the two queries (the selected field and it's alias) are both subqueries and unrelated to each other. So, there's also no possibility for mysql to distinguish what name you want to connect to what value, even if the syntax was correct...
You already use a more or less normalized relational table, so I suggest the following solution:
you select the revision ID and name in a separate query; store them in PHP and use them for whatever you want
next, you evaluate the following query into a separated result set: SELECT ps.keyname, psv.keyvalue FROM page_setting_values AS psv INNER JOIN page_settings AS ps ON ps.id = psv.setting_id WHERE psv.page_revision_id = :revision with :revision representing your revision id
you may now assemble an associated array from that result set:
$settings = [];
$result = $db->executeQuery('...')->fetchAll();
foreach($result as $setting)
{
$settings[$setting['keyname']] = $setting['keyvalue'];
}
Hope that helps ;)