Update referencing on subquery (sqlite) - sql

I have a table with md5 sums for files and use the following query to find the files which exist in one hashing-run and not in the other (oldt vs newt):
SELECT *
FROM md5_sums as oldt
WHERE NOT EXISTS (SELECT *
FROM md5_sums as newt
WHERE oldt.file = newt.file
and oldt.relpath = newt.relpath
and newt.starttime = 234)
and oldt.starttime = 123
now I want to put a flag in an extra column with an update clause, like
update md5_sums
set only_in_old = 'X'
where
and there I want a reference to the upper query as subquery, but i cannot find a proper way. Is there a possibility to use the results from the upper query for the where clause from the update-query?
(I added now some Table Screenshots with simple Table Data)
Table Description
Table Data before UPDATE
desired Table Data after UPDATE

SQLite does not support aliasing the updated table.
In your case you don't need that.
You can use the table's name md5_sums inside the subquery since you aliased the table of the SELECT statement as newt.
UPDATE md5_sums
SET only_in_old = 'X'
WHERE NOT EXISTS (
SELECT 1 FROM md5_sums AS newt
WHERE md5_sums.file = newt.file
AND md5_sums.relpath = newt.relpath
AND newt.starttime = 234
)
AND starttime = 123
See the demo.
Results:
| file | relpath | starttime | only_in_old |
| ------- | -------- | --------- | ----------- |
| abc.txt | /var/tmp | 123 | |
| abc.txt | /var/tmp | 234 | |
| def.txt | /tmp | 123 | X |
| xyz.txt | /tmp | 234 | |

I hope this helps you in converting the select statement into an update statement,
UPDATE md5_sums
SET only_in_old = 'X'
WHERE NOT EXISTS (SELECT *
FROM md5_sums newt
WHERE file = newt.file
and relpath = newt.relpath
and newt.starttime = 1551085649.7764235)
and starttime = 1551085580.009046

Related

SQL subtracting a value from 2 separate rows, in 2 separate columns

I am having trouble figuring this out... I am trying to write an SQL query to subtract 2 values from this table:
RateTable:
RecordID | Policy | Benefit | CBBR | IBBR
---------+--------+---------+-------+-------
1 | 12345 | A | $1.34 | $5.64
2 | 12345 | B | $4.56 | $0.56
3 | 12345 | C | $5.67 | $3.32
4 | 54321 | A | $2.57 | $6.24
5 | 34512 | A | $1.76 | $3.32
6 | 34512 | A | $4.56 | $1.34
I need to create a query that will return the result from the value in CBBR where Policy = 12345 and benefit = A then subtract the value in IBBR where Policy = 12345 and benefit = B ($1.34 - 0.56)
Any ideas?
I am not clear that you want the diff for only 1 value "B" or the pattern will go on if condition (Policy = 12345 and benefit ='A') to get the diff of next row.
ASSUMING diff you want to calculate for all next rows
select *,case when Benefit='A'AND Policy=12345 then CBBR-new_IBBR else CBBR end as diff from(
select *,lead(IBBR,1) over (order by RecordID ASC) as new_IBBR from <TABLE NAME>)x
Ankit Jindal has already gave a correct answeh. However, I'd like to note that there's no need to use any subquery as they can significantly slown down the performance. In this particular case, a JOIN operator is enough:
SELECT
rta.CBBR-rtb.IBBR as Result
FROM RateTable as rta
JOIN RateTable as rtb ON rtb.Policy=rta.Policy AND rtb.Benefit='B'
WHERE Policy=12345
AND Benefit='A'
As per the details mentioned in query, you need difference between CBBR & IBBR for particular conditions.
SELECT CBBR-
(SELECT IBBR
FROM RateTable
WHERE Policy = 12345
AND benefit = 'B') AS IBBR
FROM RateTable
WHERE Policy = 12345
AND benefit = 'A';
But if you need generalized query then we probably gonna use SUM or something else.
Your question requires more explanation, based on my understanding I think you should use case statement as-
Select
Case when (Policy = 12345 and benefit = A) then CBBR
When (Policy = 12345 and benefit = B) then CBBR-IBBR
END as Value
From Yourtable

Oracle set value in column when associated value is found in another table

I have two tables - referrals and bankruptcy.
Referrals
Referralno | bk_filed
----------------------
123 |
456 |
789 |
Bankruptcy
Referralno
----------
875
123
789
I would like populate the bk_filed column with a "Y" if the referralno number matches in both tables. Results would look like this.
Referralno | bk_filed
----------------------
123 | Y
456 |
789 | Y
I've tried the following merge statement but can't get it to work.
merge into LCTS.referrals r
using LCTS.bankruptcy b
on (r.referralno = b.referralno )
when matched then update
set r.bk_filed = "Y"
You can write this as an update statement, using exists and a correlated subquery for filtering:
update referrals r
set bk_filed = 'Y'
where exists (select 1 from bankruptancy b wehre b.referralno = r.referralno)

Counting points/coordinates that lie within a bounding box

I have 2 tables. The first table contains following columns: Start_latitude, start_longitude, end_latitude, end_longitude, sum. The sum column is empty and needs to be filled based on second table.
The second table contains 3 columns: point_latitude, point_longitude
Table 1
-------------------------
|45 | 50 | 46 | 51 | null|
----|---------------------
|45 | 54 | 46 | 57 | null|
--------------------------
Table2:
---------------
| 45.5 | 55.2 |
---------------
| 45.8 | 50.6 |
---------------
| 45.2 | 56 |
---------------
The null values in table1-row1 would be 1 while in row2 it would be 2. It is the count of number of points that lie within the bounding box.
I can do it in python by writing functions to read values between dataframes. How can this be done in Postgresql. This is a sample problem statement that I came up with for my situation.
Update
This version was tested on PostgreSql 9.3 using SQL Fiddle
UPDATE table1 a
SET sum = sub.point_count
FROM (SELECT a.start_lat, a.end_lat, a.start_lon, a.end_lon, COUNT(*) as point_count
FROM table1 a, table2 b
WHERE b.point_lat BETWEEN start_lat AND a.end_lat
AND b.point_lon BETWEEN a.start_lon AND a.end_lon
GROUP BY a.start_lat, a.end_lat, a.start_lon, a.end_lon) as sub
WHERE a.start_lat = sub.start_lat
AND a.end_lat = sub.end_lat
AND a.start_lon = sub.start_lon
AND a.end_lon = sub.end_lon;
Original answer
Here is my solution, it is tested on MySQL but there is nothing specific about this code so it should work on PostgreSql as well
UPDATE table1 a,
(SELECT a.start_lat, a.end_lat, a.start_lon, a.end_lon, COUNT(*) as count
FROM table1 a, table2 b
WHERE b.point_lat BETWEEN start_lat AND a.end_lat
AND b.point_lon BETWEEN a.start_lon AND a.end_lon
GROUP BY a.start_lat, a.end_lat, a.start_lon, a.end_lon) as sub
SET sum = count
WHERE a.start_lat = sub.start_lat
AND a.end_lat = sub.end_lat
AND a.start_lon = sub.start_lon
AND a.end_lon = sub.end_lon
Note that this query would be much shorter if table1 contained a PK Id column.

Including records that are missing in another dataset

I'm trying to do something along the lines of a WHERE NOT EXISTS or WHERE NOT IN, but am struggling with the syntax.
This is the results set I've got so far, let's called it PlanActStaff:
SELECT
CTE_PlanStaff.RegisterID,
CTE_PlanStaff.TT_ActivityDate,
CTE_PlanStaff.TT_ActivityTime,
CTE_PlanStaff.TT_StaffID,
CTE_ActStaff.ActStaffID
FROM
CTE_PlanStaff
INNER JOIN
CTE_ActStaff
ON
CTE_PlanStaff.RegisterID = CTE_ActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = CTE_ActStaff.ActSessionDate
AND
CTE_PlanStaff.TT_ActivityTime = CTE_ActStaff.ActSessionStartTime
For each record in this result set I want the query to go back and check my CTE_PlanStaff CTE to see whether the ActStaffID exists for the current combination of RegisterID, TT_ActivityDate and TT_ActivityTime in CTE_PlanStaff.
So for example, if a record being checked in PlanActStaff looked like this:
| RegisterID | TT_ActivityDate | TT_ActivityTime | TT_StaffID | ActStaffID |
|------------|-----------------|-----------------|------------|------------|
| 98688 | 2016-01-04 | 11:20 | 2453 | 2067 |
CTE_PlanStaff would then be filtered on the same combination of RegisterID, TT_ActivityDate and TT_ActivityTime, so CTE_PlanStaff might then have these records to compare:
| RegisterID | TT_ActivityDate | TT_ActivityTime | TT_StaffID |
|------------|-----------------|-----------------|------------|
| 98688 | 2016-01-04 | 11:20 | 2500 |
| 98688 | 2016-01-04 | 11:20 | 2453 |
I'd then like the ActStaffID value of 2067 checked against each TT_StaffID in the filtered CTE_PlanStaff and if the ActStaffID isn't listed to leave that record showing in my PlanActStaff query.
I've tried to adapt PlanActStaff as follows...
SELECT *
FROM
(
SELECT
CTE_PlanStaff.RegisterID,
CTE_PlanStaff.TT_ActivityDate,
CTE_PlanStaff.TT_ActivityTime,
CTE_PlanStaff.TT_StaffID,
CTE_ActStaff.ActStaffID
FROM
CTE_PlanStaff
INNER JOIN
CTE_ActStaff
ON
CTE_PlanStaff.RegisterID = CTE_ActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = CTE_ActStaff.ActSessionDate
AND
CTE_PlanStaff.TT_ActivityTime = CTE_ActStaff.ActSessionStartTime
) PlanActStaff
WHERE
ActStaffID NOT IN (
SELECT *
FROM
CTE_PlanStaff
WHERE
CTE_PlanStaff.RegisterID = PlanActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = PlanActStaff.TT_ActivityDate
AND
CTE_PlanStaff.TT_ActivityTime = PlanActStaff.TT_ActivityTime
)
...but I get the following error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS.
I started looking at WHERE NOT EXISTS, but I can't figure out how to both filter CTE_PlanStaff against the current record and then check the staffID fields.
WHERE
ActStaffID NOT IN (
SELECT *
FROM
CTE_PlanStaff
WHERE
CTE_PlanStaff.RegisterID = PlanActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = PlanActStaff.TT_ActivityDate
AND
CTE_PlanStaff.TT_ActivityTime = PlanActStaff.TT_ActivityTime
)
you should select only one field to be compared against 'ActStaffID'

update a table from another table and add new values

How would I go about updating a table by using another table so it puts in the new data and if it doesnt match on an id it adds the new id and the data with it. My original table i much bigger than the new table that will update it. and the new table has a few ids that aren't in the old table but need to be added.
for example I have:
Table being updated-
+-------------------+
| Original Table |
+-------------------+
| ID | Initials |
|------+------------|
| 1 | ABC |
| 2 | DEF |
| 3 | GHI |
and...
the table I'm pulling data from to update the other table-
+-------------------+
| New Table |
+-------------------+
| ID | Initials |
|------+------------|
| 1 | XZY |
| 2 | QRS |
| 3 | GHI |
| 4 | ABC |
then I want my Original table to get its values that match up to be updated by the new table if they have changed, and add any new ID rows if they aren't in the original table so in this example it would look like the New Table.
+-------------------+
| Original Table |
+-------------------+
| ID | Initials |
|------+------------|
| 1 | XZY |
| 2 | QRS |
| 3 | GHI |
| 4 | ABC |
You can use MERGE statement to put this UPSERT operation in one statement but there are issues with merge statement I would split it into two Statements, UPDATE and INSERT
UPDATE
UPDATE O
SET O.Initials = N.Initials
FROM Original_Table O INNER JOIN New_Table N
ON O.ID = N.ID
INSERT
INSERT INTO Original_Table (ID , Initials)
SELECT ID , Initials
FROM New_Table
WHERE NOT EXISTS ( SELECT 1
FROM Original_Table
WHERE ID = Original_Table.ID)
Important Note
Reason why I suggested to avoid using merge statement read this article Use Caution with SQL Server's MERGE Statement by Aaron Bertrand
You need to use the MERGE statement for this:
MERGE original_table AS Target
USING updated_table as Source
ON original_table.id = updated_table.id
WHEN MATCHED THEN UPDATE SET Target.Initials = Source.Initials
WHEN NOT MATCHED THEN INSERT(id, Initials) VALUES(Source.id, Source.Initials);
You have not specified, what happens in case the valuesin original table are not found in the updated one. But, just in case, you can add this to remove them from original table:
WHEN NOT MATCHED BY SOURCE
THEN DELETE
if you can use loop in PHP and go through all tables and copy one by one to another table.
another option
DECLARE #COUT INT
SET #COUT = SELECT COUNT(*) FROM New_Table
WHILE (true)
BEGIN
IF #COUT = 0
BREAK;
SET #COUT = #COUT - 1
DECLARE #id INT
DECLARE #ini VARCHAR(20)
SET #id = (SELECT id FROM New_Table);
SET #ini = (SELECT Initials FROM New_Table);
IF (SELECT COUNT(*) FROM Original_Table WHERE id=#id ) > 0
UPDATE SET ID = #id,Initials = #ini FROM Original_Table WHERE id = #id;
insert into Original_Table values(#id,#ini);
END
GO