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.
Related
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.
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);
EDIT OK so the main problem here was initial column1 FROM table1 with the join. Even that column1 has to be fully defined as table1.column1 even tho it is next to the FROM which seems at best odd to me. But I guess this is a newb error and I hope other newbs will find this useful.
//========================================================================
Have used simple joins before without problems. I thought the table.column format was unambiguous.
Warning is:
Integrity constraint violation: 1052 Column 'transmissionProgramID'
in field list is ambiguous'
The SQL is:
SELECT transmissionProgramID FROM transmissionProgramOwner
JOIN transmissionProgram on transmissionProgram.transmissionProgramID
= transmissionProgramOwner.transmissionProgramID WHERE
ownerType = '$ownerType' AND ownerID = '$ownerID' ORDER BY startDate
The two table transmissionProgramOwner and transmissionProgram both have fields called transmissionProgramID. I just cannot see how the table.column leaves anything ambiguous.
Sure it is something simple but I cannot see it. And I apologize for the long variable names but helps me keep things clear.
Additional info: Both transmissionProgramID are set to unique in both tables. I have tried every flaovor of JOIN but I think a simple join is allowed which just returns all records that match... In any case have tried every type of join just to make sure.
Friend try this
SELECT t1.transmissionProgramID FROM transmissionProgramOwner t1
JOIN transmissionProgram t2 on t2.transmissionProgramID
= t1.transmissionProgramID WHERE
t1.ownerType = '$ownerType' AND t1.ownerID = '$ownerID' ORDER BY t1.startDate;
change to
SELECT transmissionProgram.transmissionProgramID FROM
transmissionProgramOwner JOIN transmissionProgram on
'transmissionProgram.transmissionProgramID'
= 'transmissionProgramOwner.transmissionProgramID' WHERE ownerType = '$ownerType' AND ownerID = '$ownerID' ORDER BY startDate
I need to do something like this,
My two tables have the same signature, but different class so It suppose to work but it is not working.
var myTable;
if (booleanVariable == true)
{
myTable = table1;
}
else
{
myTable = table2;
}
var myLinq1 = from p in myTable
join r in myOtherTable
select p;
In this case, I have to initialize myTable
I have tried also,
var myTable= table2;
if (booleanVariable == true)
{
myTable = table1;
}
var myLinq1 = from p in myTable
join r in myOtherTable
select p;
then var is type table2, then it can't be changed to table1 type.
I need help, I don't want to make a copy paste of all the code. the linq query is huge, and it s nested with 5 or 6 queries. also I have to do this on 12 different methods.
Thanks a lot for your help.
Don't know if this will work, never tried it, but...
If both classes can implement the same interface or share a base class, could you maybe do:
var q = (booleanVariable)
? from p in myTable1 select (ISomeInterface)p
: from p in myTable2 select (ISomeInterface)p;
If you use this often, you can put this into its own method - I believe it will return IQueryable<ISomeInterface>.
Then connect to the rest of the LINQ query using the LINQ methods instead of the LINQ C# syntax (i.e. OrderBy() instead of orderby). I just don't know if LINQ-to-SQL will be smart enough to translate this into the correct SQL query.
But I agree with Jon's comment - this is probably bad design, and should be revisited. If you can't reorganize the tables themselves, and if you only need read access, how about a view that unions the two tables together, then tie that view into your LINQ-to-SQL structure.
I realized that i was using a varchar attribute as a index/key in a query, and that is killing my query performance. I am trying to look in my precienct table and get the integer ID, and then update my record in the household table with the new int FK, placed in a new column. this is the sql i have written thus far. but i am getting a
Error 1093 You can't specify target table 'voterfile_household' for update in FROM clause, and i am not sure how to fix it.
UPDATE voterfile_household
SET
PrecID = (SELECT voterfile_precienct.ID
FROM voterfile_precienct INNER JOIN voterfile_household
WHERE voterfile_precienct.PREC_ID = voterfile_household.Precnum);
Try:
update voterfile_household h, voterfile_precienct p
set h.PrecID = p.ID
where p.PREC_ID = h.Precnum
Take a look at update reference here.
Similarly, you can use inner join syntax as well.
update voterfile_household h inner join voterfile_precienct p on (h.Precnum = p.PREC_id)
set h.PrecID = p.ID
What if the subquery returns more than one result? That's why it doesn't work.
On SQL Server you can get this type of thing to work if the subquery does "SELECT TOP 1 ...", not sure if mysql will also accept it if you add a "limit 1" to the subquery.
I also think this is pretty much a duplicate of this question ("Can I have an inner SELECT inside of an SQL UPDATE?") from earlier today.
Firstly, your index on a varchar isn't always a bad thing, if it is not a key you can shrink how much of the field you index to only index say the first 10 chars or so.
Secondly, it won't let you do this as if it is a set that is returned it could break.