Update table column based on value of key in other column POSTGRES - sql

My table name is companies having is_nse,a boolean column and exchanges column type json having value like "[{"exchange":"NSE","ticker":"ABC"},{"exchange":"BSE","ticker":"ABC"}]"
Now i have this query
update companies set is_nse=0 from (SELECT is_nse, obj.value->>'exchange' As exch FROM (SELECT * FROM companies WHERE sector is not null) u JOIN LATERAL json_array_elements(exchanges) obj(value) ON obj.value->>'exchange' = 'BSE')y
But it is updating all the rows in companies table rather than rows of the subquery.Can anybody tell me where am I going wrong?

You need to connect the companies in the update to the from clause. Assuming you have an id, you can do:
update companies
set is_nse = 0
from (select c.*
from companies u join lateral
json_array_elements(exchanges) obj(value)
on obj.value->>'exchange' = 'BSE'
where u.sector is not null
) y
where y.companyid = companies.companyid ;

Related

Insert into newly created column

I have a Students table with 2 col as Rollno and Marks with 12 records
I added another column in students table as Name. How do I fill Names with 12 records from another table in SQL Server?
I tried this:
SELECT * FROM [SampleDB].[dbo].[Student_SQL]
insert into Student_SQL(name)
select name
FROM [School].[dbo].[StudentMaster]
update [Student_SQL]
set name = 'David'
where RollNo = 4`
I think you want the upate/join syntax. Assuming that the two tables relate through column rollno:
update ss
set ss.name = sm.name
from student_sql ss
inner join student_master sm on sm.rollno = ss.rollno
The upside of this approach is that it filters the rows and only update those that match in the master table.
in order to do this, you need to have column in common for both tables
update [Student_SQL] s
set name = (select name from other_table o where o.roll_no = s.roll_no)

Oracle "NOT IN" not returning correct result?

I'm comparing two tables that share unique values between each other using NOT IN function in Oracle but I'm getting
select count(distinct CHARGING_ID) from BILLINGDB201908 where CDR_TYPE='GPRSO'
the output is: 521254 for all charging ids --< this is the total unique charging ID's in BILLINGDB201908
Now I want to find id's in table BILLINGDB201908 that also exist in table CBS_CHRG_ID_AUG
select count(distinct CHARGING_ID) from BILLINGDB201908 where CDR_TYPE='GPRSO'
AND charging_id IN (select CHARGINGID from CBS_CHRG_ID_AUG);
--- the result back315567 charging ID exist BILLINGDB201908 and also exist in CBS_CHRG_ID_AUG
Now I want to find charging ids that not exist in CBS_CHRG_ID_AUG but exist BILLINGDB201908
select count(distinct CHARGING_ID) from prmdb.CDR_TAPIN_201908#prmdb where CDR_TYPE='GPRSO'
AND charging_id NOT IN (select CHARGINGID from CBS_CHRG_ID_AUG);
--the result back 0 !? I should get 205687 exactly because 521254-315567 = 205687 ?
NOT IN returns no rows if any value from the subquery is NULL. Hence, I strongly, strongly recommend NOT EXISTS:
SELECT count(distinct CHARGING_ID)
FROM prmdb.CDR_TAPIN_201908#prmdb ct
WHERE CDR_TYPE = 'GPRSO' AND
NOT EXISTS (SELECT 1
FROM CBS_CHRG_ID_AUG ccia
WHERE ccia.charging_id = ct.charging_id
);
I also recommend changing your first query to EXISTS. In fact, just don't use IN and NOT IN with subqueries, and you won't have this problem.
The missing record is having null value CHARGINGID.
Please try doing select where CHARGINGID is null vs is not null
I would recommend not exists rather than not in; it is null-safe, and usually more efficient:
select count(distinct charging_id)
from billingdb201908 b
where
b.cdr_type = 'gprso'
and not exists (select 1 from cbs_chrg_id_aug a where a.chargingid = b.chargingid)
You can get this list using LEFT OUTER JOIN.
SQL to return list of charging ids that not exist in CBS_CHRG_ID_AUG but exist BILLINGDB201908 -
select count(distinct CHARGING_ID)
from prmdb.CDR_TAPIN_201908#prmdb a
left join CBS_CHRG_ID_AUG b on a.CHARGING_ID = b.CHARGINGID
where a.CDR_TYPE='GPRSO' and b.CHARGINGID is null;
There are two dangers with not in when the subquery key may contain nulls:
If there actually is a null value, you may not get the result you were expecting (as you have found). The database is actually correct, even though nobody in the history of SQL has ever expected this result.
Even if all key values are populated, if it is possible for the key column to be null (if it is not defined as not null) then the database has to check in case there is a null value, so queries are limited to inefficient row by row filter operations, which can perform disastrously for large volumes. (This was true historically, although these days there is a Null-aware anti-join and so the performance issue may not be so disastrous.)
create table demo (id) as select 1 from dual;
select * from demo;
ID
----------
1
create table table_with_nulls (id) as (
select 2 from dual union all
select null from dual
);
select * from table_with_nulls;
ID
----------
2
select d.id
from demo d
where d.id not in
( select id from table_with_nulls );
no rows selected
select d.id
from demo d
where d.id not in
( select id from table_with_nulls
where id is not null );
ID
----------
1
The reason is that 1 <> null is null, not false. If you substitute a fixed list for the not in subquery, it would be:
select d.id
from demo d
where d.id not in (2, null);
which is really the same thing as
select d.id
from demo d
where d.id <> 2 and d.id <> null;
Obviously d.id <> null will never be true. This is why your not in query returned no rows.

Select records from table A where 4 of its columns equal to 4 of table's B columns

Basically, I have two tables, a [students] table and a [units_allocation] table.
Both tables have columns named course_abbr, course_name, month_of_admission and year_of_admission.
I want to select records from the students table where the above 4 columns in both tables have similar values.
An inner join or exists is a typical solution:
select s.*
from students s
where exists (select 1
from units_allocation ua
where s.course_abbr = ua.course_abbr and
s.course_name = ua.course_name and
s.month_of_admission = ua.month_of_admission and
s.year_of_admission = ua.year_of_admission
);
One way is using INTERSECT(work's for SQL Server and Oracle)
SELECT course_abbr, course_name, month_of_admission,year_of_admission
FROM students
INTERSECT
SELECT course_abbr, course_name, month_of_admission,year_of_admission
FROM units_allocation
or use EXISTS in case of Mysql
SELECT *
FROM students s
WHERE EXISTS (SELECT 1
FROM units_allocation u
WHERE s.course_abbr = u.course_abbr
AND s.course_name = u.course_name
AND s.month_of_admission = u.month_of_admission
AND s.year_of_admission = u.year_of_admission)

Get latest record from second table left joined to first table

I have a candidate table say candidates having only id field and i left joined profiles table to it. Table profiles has 2 fields namely, candidate_id & name.
e.g. Table candidates:
id
----
1
2
and Table profiles:
candidate_id name
----------------------------
1 Foobar
1 Foobar2
2 Foobar3
i want the latest name of a candidate in a single query which is given below:
SELECT C.id, P.name
FROM candidates C
LEFT JOIN profiles P ON P.candidate_id = C.id
GROUP BY C.id
ORDER BY P.name;
But this query returns:
1 Foobar
2 Foobar3
...Instead of:
1 Foobar2
2 Foobar3
The problem is that your PROFILES table doesn't provide a reliable means of figuring out what the latest name value is. There are two options for the PROFILES table:
Add a datetime column IE: created_date
Define an auto_increment column
The first option is the best - it's explicit, meaning the use of the column is absolutely obvious, and handles backdated entries better.
ALTER TABLE PROFILES ADD COLUMN created_date DATETIME
If you want the value to default to the current date & time when inserting a record if no value is provided, tack the following on to the end:
DEFAULT CURRENT_TIMESTAMP
With that in place, you'd use the following to get your desired result:
SELECT c.id,
p.name
FROM CANDIDATES c
LEFT JOIN PROFILES p ON p.candidate_id = c.id
JOIN (SELECT x.candidate_id,
MAX(x.created_date) AS max_date
FROM PROFILES x
GROUP BY x.candidate_id) y ON y.candidate_id = p.candidate_id
AND y.max_date = p.created_date
GROUP BY c.id
ORDER BY p.name
Use a subquery:
SELECT C.id, (SELECT P.name FROM profiles P WHERE P.candidate_id = C.id ORDER BY P.name LIMIT 1);

what's the best way to design dynamic key-value pairs in mysql?

I need to attach unlimited attributes to a record in a table, and I've already designed a system using #3 below using mysql. Unfortunately I am finding that searching across a million records is getting slow. Is #2 a better approach, or is there a better way alltogether? Is this a case for using a view? I'd like to have my keys table separate so I know what attributes are being stored for each record.
1: simple:
table records: id, recordname, valname
select recordname from records where valname = 'myvalue'
2: a little more complex:
table records: id recordname
table keyvalues: id recordid keyname valname
select r.recordname
from records r
right join keyvalues kv on kv.recordid = r.id
and kv.keyname='mykey'
and kv.valname = 'myvalue'
3: most complex:
table records: id recordname
table keys: id keyname
table values: id recordid keyid valname
select r.recordname
from records r
right join keys k on k.keyname='mykey'
right join values v on v.recordid = r.id
and v.keyid = k.id
and v.valname = 'myvalue'
I would use inner joins. This will give a smaller result set and the one you want.
Did you try this query?
select r.recordname
from records r
left join values link on link.recordid = r.id and link.valname = 'myvalue'
left join keys k on r.keyid = link.key.id and k.keyname = 'mykey'
However, I think the real way to do it is to have 4 tables
table records: id recordname
table keys: id keyname
table values : id valuename
table joins : id recordid keyid valueid
Then (with the right indexes) you can have a query like this
select r.recordname
from joins j
left join records r on j.recordid = r.id
left join keys k on j.keyid = k.id
left join values v on j.valueid = v.id
where v.valuename = 'myvalue' and k.keyname = 'mykey'
This should be quite fast... all it has to do is find the id in values and keys and then do a scan on j. If you have the right indexes these will be quick.