Pass column name as argument - Postgres and Node JS - node.js

I have a query (Update statement) wrapped in a function and will need to perform the same statement on multiple columns during the course of my script
async function update_percentage_value(value, id){
(async () => {
const client = await pool.connect();
try {
const res = await client.query('UPDATE fixtures SET column_1_percentage = ($1) WHERE id = ($2) RETURNING *', [value, id]);
} finally {
client.release();
}
})().catch(e => console.log(e.stack))
}
I then call this function
update_percentage_value(50, 2);
I have many columns to update at various points of my script, each one needs to be done at the time. I would like to be able to just call the one function, passing the column name, value and id.
My table looks like below
CREATE TABLE fixtures (
ID SERIAL PRIMARY KEY,
home_team VARCHAR,
away_team VARCHAR,
column_1_percentage INTEGER,
column_2_percentage INTEGER,
column_3_percentage INTEGER,
column_4_percentage INTEGER
);
Is it at all possible to do this?

I'm going to post the solution that was advised by Sehrope Sarkuni via the node-postgres GitHub repo. This helped me a lot and works for what I require:
No column names are identifiers and they can't be specified as parameters. They have to be included in the text of the SQL command.
It is possible but you have to build the SQL text with the column names. If you're going to dynamically build SQL you should make sure to escape the components using something like pg-format or use an ORM that handles this type of thing.
So something like:
const format = require('pg-format');
async function updateFixtures(id, column, value) {
const sql = format('UPDATE fixtures SET %I = $1 WHERE id = $2', column);
await pool.query(sql, [value, id]);
}
Also if you're doing multiple updates to the same row back-to-back then you're likely better off with a single UPDATE statement that modifies all the columns rather than separate statements as they'd be both slower and generate more WAL on the server.

To get the column names of the table, you can query the information_schema.columns table which stores the details of column structure of your table, this would help you in framing a dynamic query for updating a specific column based on a specific result.
You can get the column names of the table with the help of following query:
select column_name from information_schema.columns where table_name='fixtures' and table_schema='public';
The above query would give you the list of columns in the table.
Now to update each one for a specific purpose, You can store the result set of column name to a variable and pass that variable to the function to perform the required action.

Related

Fetch jsonb column of postgres db

I am using node-postgres to select and insert data into postgres. I have some column of jsonb type which I am fetching from db by using below query
getEmployee() {
return SELECT empId, empData FROM employee WHERE empId = $1;
}
where empData is jsonb type of column. Below is code snippet which use above query.
const employee = await DBService.query(pgObj.getEmployee(), [empId]);
when I am trying to get empData from employee I am getting empty value.
const { empData } = employee;
I am not sure what I am missing here. Is this the correct way to fetch josnb column of postgreas db in nodejs?
Are you sure empdata is even populated, in the database? Maybe it's empty.
Also, what are the jsonb fields of empdata?
To get the actual sub-fields of empdata, you need the ->> operator. eg:
get the whole json object as text
SELECT empId, empData::text
FROM employee where empId = $1
get individual attributes
SELECT empId, empData->>annual_pay as salary
FROM employee WHERE empId = $1;
etc...
You can also try
Have a look here: https://kb.objectrocket.com/postgresql/how-to-query-a-postgres-jsonb-column-1433
I haven't tried these out, I'm not in front of postgres right now.

Querying cassandra database with an array

I am trying to query my cassandra database to return data from a list of names held on an array server side. This is held as an array.
I know the data I am accessing is stored as a string in my database and so I have appended single quotes around it (I have tried with and without this but no luck).
Here is my query.
const arr = ["ukcust1","ukcust2","ukcust5"];
//Here I append single quotes before and after to each string if needed
const query = "SELECT * FROM table_name WHERE name = ?";
client.execute(query, arr, { prepare:true }, function (err, result) {
..//Code
};
What am I missing here? I want the query to be:
SELECT * FROM table_name WHERE name = each of the names in the array 'arr';
If name were a clustering key, then you could query with "in" and "allow filtering" like this:
select * from table_name where name in ('ukcust1','ukcust2','ukcust3') allow filtering
Assuming name is not a clustering key, you could use a clustering key (e.g., date_of_birth) if it made logical sense -- that is, if filtering by date made sense in relation to the name -- like this:
select * from table_name where date_of_birth in (1969, 1972) name in ('ukcust1','ukcust2','ukcust3') allow filtering
If you can't do either of those things, you will need to loop through the array with Javascript (e.g., foreach).
The correct input of the query parameters is an array of values. In this case, it would be an array of parameters containing a single item, that is an array of names.
const arr = ["ukcust1","ukcust2","ukcust5"];
const query = "SELECT * FROM table_name WHERE name = ?";
// Note the array containing a single item
const parameters = [ arr ];
client.execute(query, parameters, { prepare: true }, callback);
See more info in the documentation: https://docs.datastax.com/en/developer/nodejs-driver/3.5/faq/#how-can-i-use-a-list-of-values-with-the-in-operator-in-a-where-clause

Access column value from within knex query

I'd like to update the value of column A by applying a function to column B.
Is there a simple solution of the form:
knex('table')
.update({
colA: func(${colB})
})
Yes, there is a way to do this within Knex.
For SQL functions which don’t have explicit support in Knex you use knex.raw(SQLstring, parmArray) to encapsulate a SQL snippet or knex.schema.raw(...) to produce an entire SQL statement. And you use single question marks ? for value replacements, and double question marks ?? for field identifier replacements. (see link)
So the SQL: UPDATE table SET colA = func(colB)
... can be produced by including a SQL snippet: (you were close)
knex('table')
.update({
colA: knex.raw( 'func(??)', ['colB'] )
})
... or as full raw SQL:
knex.schema.raw( 'UPDATE table SET ?? = func(??)', ['colA', 'colB'] )
Cheers, Gary.

Error in Linq: The text data type cannot be selected as DISTINCT because it is not comparable

I've a problem with LINQ. Basically a third party database that I need to connect to is using the now depreciated text field (I can't change this) and I need to execute a distinct clause in my linq on results that contain this field.
I don't want to do a ToList() before executing the Distinct() as that will result in thousands of records coming back from the database that I don't require and will annoy the client as they get charged for bandwidth usage. I only need the first 15 distinct records.
Anyway query is below:
var query = (from s in db.tSearches
join sc in db.tSearchIndexes on s.GUID equals sc.CPSGUID
join a in db.tAttributes on sc.AttributeGUID equals a.GUID
where s.Notes != null && a.Attribute == "Featured"
select new FeaturedVacancy
{
Id = s.GUID,
DateOpened = s.DateOpened,
Notes = s.Notes
});
return query.Distinct().OrderByDescending(x => x.DateOpened);
I know I can do a subquery to do the same thing as above (tSearches contains unique records) but I'd rather a more straightfoward solution if available as I need to change a number of similar queries throughout the code to get this working.
No answers on how to do this so I went with my first suggestion and retrieved the unique records first from tSearch then constructed a subquery with the non unique records and filtered the search results by this subquery. Answer below:
var query = (from s in db.tSearches
where s.DateClosed == null && s.ConfidentialNotes != null
orderby s.DateOpened descending
select new FeaturedVacancy
{
Id = s.GUID,
Notes = s.ConfidentialNotes
});
/* Now filter by our 'Featured' attribute */
var subQuery = from sc in db.tSearchIndexes
join a in db.tAttributes on sc.AttributeGUID equals a.GUID
where a.Attribute == "Featured"
select sc.CPSGUID;
query = query.Where(x => subQuery.Contains(x.Id));
return query;

Subsonic 3 Simple Query inner join sql syntax

I want to perform a simple join on two tables (BusinessUnit and UserBusinessUnit), so I can get a list of all BusinessUnits allocated to a given user.
The first attempt works, but there's no override of Select which allows me to restrict the columns returned (I get all columns from both tables):
var db = new KensDB();
SqlQuery query = db.Select
.From<BusinessUnit>()
.InnerJoin<UserBusinessUnit>( BusinessUnitTable.IdColumn, UserBusinessUnitTable.BusinessUnitIdColumn )
.Where( BusinessUnitTable.RecordStatusColumn ).IsEqualTo( 1 )
.And( UserBusinessUnitTable.UserIdColumn ).IsEqualTo( userId );
The second attept allows the column name restriction, but the generated sql contains pluralised table names (?)
SqlQuery query = new Select( new string[] { BusinessUnitTable.IdColumn, BusinessUnitTable.NameColumn } )
.From<BusinessUnit>()
.InnerJoin<UserBusinessUnit>( BusinessUnitTable.IdColumn, UserBusinessUnitTable.BusinessUnitIdColumn )
.Where( BusinessUnitTable.RecordStatusColumn ).IsEqualTo( 1 )
.And( UserBusinessUnitTable.UserIdColumn ).IsEqualTo( userId );
Produces...
SELECT [BusinessUnits].[Id], [BusinessUnits].[Name]
FROM [BusinessUnits]
INNER JOIN [UserBusinessUnits]
ON [BusinessUnits].[Id] = [UserBusinessUnits].[BusinessUnitId]
WHERE [BusinessUnits].[RecordStatus] = #0
AND [UserBusinessUnits].[UserId] = #1
So, two questions:
- How do I restrict the columns returned in method 1?
- Why does method 2 pluralise the column names in the generated SQL (and can I get round this?)
I'm using 3.0.0.3...
So far my experience with 3.0.0.3 suggests that this is not possible yet with the query tool, although it is with version 2.
I think the preferred method (so far) with version 3 is to use a linq query with something like:
var busUnits = from b in BusinessUnit.All()
join u in UserBusinessUnit.All() on b.Id equals u.BusinessUnitId
select b;
I ran into the pluralized table names myself, but it was because I'd only re-run one template after making schema changes.
Once I re-ran all the templates, the plural table names went away.
Try re-running all 4 templates and see if that solves it for you.

Resources