SQL to set a value based on a value from a diffrent table automatically - sql

The title may not be that helpful but what I am trying to do is this.
For simplicity's sake I have two tables one called logs and another called Log controls
In LOGS I have and a log event column, this is automatically populated by imported information. On the LOG CONTROLS I have a manually entered list of Log events (to match the ones coming in) and I have this table to have them assigned ID numbers and other details about the event.
What I need to do is have a column in the LOGS table which looks at the Log events, matches it to the ID from the LOG CONTROLS table and assigns the ID into the LOGS table.
I have seen a few methods of changing information in columns based of information in other tables but all of these seem to be one way checks i.e if ID = X change to VALUE FROM OTHER TABLE where as what I need is IF VALUE = X FROM OTHER TABLE CHANGE ID FIELD TO = Y FROM OTHER TABLE
Below is a mock up of the tables.
+----+-----------+----------+------------+
| ID | Date_Time | Event | Control ID|
+----+-----------+----------+------------+
| 1 | 0/0/0 | Shutdown | |
| 2 | 0/0/0 | Start up | |
| 3 | 0/0/0 | Error | |
| 4 | 0/0/0 | Info | |
| 5 | 0/0/0 | Shutdown | |
| 6 | 0/0/0 | Error | |
+----+-----------+----------+------------+
+-------------------+----------+--------+-------+
| Control ID | Event | Export | Flag |
+-------------------+----------+--------+-------+
| 1 | Shutdown | TRUE | TRUE |
| 2 | Start up | TRUE | FALSE |
| 3 | Error | TRUE | TRUE |
| 4 | Info | TRUE | FALSE |
+-------------------+----------+--------+-------+
So I need the Control ID in the first table to match the control ID from the second table depending on what the event was.
I hope this makes sense.
Any help or advice would be greatly appreciated.

From your description, it seems that a simple UPDATE statement is all you need:
update logs
set control_id = c.control_id
from log_controls as c
where c.event = logs.event;

Related

How to query the metadata(such as ttl) of record from aql?

Assume you have a set as follows:
+-------+-------+
| PK | value |
+-------+-------+
| "pk1" | 24 |
+-------+-------+
1 row in set (0.105 secs)
How to get the metadata for this?
To get the metadata, all you need to do is run this command before running the query:
set RECORD_PRINT_METADATA true
Now, when you query the set
select * from test.segments
you can see additional metadata of the set, as follows:
+-------+-------+--------------------------------+------------+-------+-------+
| PK | value | {edigest} | {set} | {ttl} | {gen} |
+-------+-------+--------------------------------+------------+-------+-------+
| "pk1" | 24 | "Rn/5rHEQGWvPOSBK+vHRMyLkFyo=" | "segments" | 57 | 1 |
+-------+-------+--------------------------------+------------+-------+-------+
1 row in set (0.175 secs)
NOTE:
The command has to be run just once. It holds true for all the queries that come after it.
To go back to the default behaviour, set the argument to false

Audit data migration into Oracle

I am having a task to migrate data from another database to Oracle database.
And data from previous database has audit information, i.e. tracking of create/update of records with update_time and update_user. For simplicity, let's assume the previous database I am talking about is an excel file of the following format:
Key | Value | Update_Time | Update_User |
----|-------|-------------|-------------|
a | 1 | 23/04/2020 | user1 |
b | 2 | 21/04/2020 | user2 |
a | 3 | 20/04/2020 | user1 |
a | 4 | 19/04/2020 | user5 |
a | 5 | 18/04/2020 | user2 |
What is the best practice to move data into Oracle such that user can still query those audit info along with the new audit given that the data is now being saved to a new table in Oracle below? Does Oracle provide any native solution for this? I try Oracle Flashback, but not sure how to include those previous audit, because as I understand, we can only query Flashback for data change from now on. Ideally, I want to store only the latest data table in Oracle like this, as they are the actual active data:
Key | Value | Last_Update_Time | Last_Update_User |
----|-------|------------------|------------------|
a | 1 | 23/04/2020 | user1 |
b | 2 | 21/04/2020 | user2 |
Let's say user continue edit row with key b on 24/04/2020, then I want to fetch those result for UI display (currently I am using python sqlalchemy to access the db, but a solution with a sql query should be fine for the start)
Key | Value | Update_Time | Update_User |
----|-------|-------------|-------------|
b | 7 | 24/04/2020 | user2 | ---> this is an update on the new oracle table above
a | 1 | 23/04/2020 | user1 | ---> those rows below I want to somehow load into the oracle without explicitly create a new table for it
b | 2 | 21/04/2020 | user2 |
a | 3 | 20/04/2020 | user1 |
a | 4 | 19/04/2020 | user5 |
a | 5 | 18/04/2020 | user2 |
After the change, the main data table in Oracle should look below
Key | Value | Last_Update_Time | Last_Update_User |
----|-------|------------------|------------------|
a | 1 | 23/04/2020 | user1 |
b | 7 | 24/04/2020 | user2 |
YOu can use the below select query
SELECT AD.* FROM Audit_table AD,
(SELECT Key,Max(Update_time) Updated_Time,Last_updated_USer
From Audit_table
group by Key,Last_updated_USer)rec
where AD.Key=rec.Key
AND AD.Updated_Time=rec.Updated_Time
AND AD.Last_updated_USer=rec.Last_updated_USer;

How to add data or change schema to production database

I am new to working with databases and I want to make sure I understand the best way to add or remove data from a database without making a mess of any related data.
Here is a scenario I am working with:
I have a Tags table, with an Identity ID column. The Tags can be selected via the web application to categorize stories that are submitted by a user. When the database was first seeded; like tags were seeded in order together. As you can see all the Campuses (cities) were 1-4, the Colleges (subjects) are 5-7, and Populations are 8-11.
If this database is live in production and the client wants to add a new Campus (City) tag, what is the best way to do this?
All the other city tags are sort of organized at the top, it seems like the only option is to insert any new tags at to bottom of the table, where they will end up taking whatever the next ID available is. I suppose this is fine because the Display category column will allow us to know which categories these new tags actually belong to.
Is this typical? Is there better ways to set up the database or handle this situation such that everything remains more organized?
Thank you
+----+------------------+---------------+-----------------+--------------+--------+----------+
| ID | DisplayName | DisplayDetail | DisplayCategory | DisplayOrder | Active | ParentID |
+----+------------------+---------------+-----------------+--------------+--------+----------+
| 1 | Albany | NULL | 1 | 0 | 1 | NULL |
| 2 | Buffalo | NULL | 1 | 1 | 1 | NULL |
| 3 | New York City | NULL | 1 | 2 | 1 | NULL |
| 4 | Syracuse | NULL | 1 | 3 | 1 | NULL |
| 5 | Business | NULL | 2 | 0 | 1 | NULL |
| 6 | Dentistry | NULL | 2 | 1 | 1 | NULL |
| 7 | Law | NULL | 2 | 2 | 1 | NULL |
| 8 | Student-Athletes | NULL | 3 | 0 | 1 | NULL |
| 9 | Alumni | NULL | 3 | 1 | 1 | NULL |
| 10 | Faculty | NULL | 3 | 2 | 1 | NULL |
| 11 | Staff | NULL | 3 | 3 | 1 | NULL |
+----+------------------+---------------+-----------------+--------------+--------+----------+
The terms "top" and "bottom" which you use aren't really applicable. "Albany" isn't at the "Top" of the table - it's merely at the top of the specific view you see when you query the table without specifying a meaningful sort order. It defaults to a sort order based on the Id or an internal ROWID parameter, which isn't the logical way to show this data.
Data in the table isn't inherently ordered. If you want to view your tags organized by their category, simply order your query by DisplayCategory (and probably by DisplayOrder afterwards), and you'll see your data properly organized. You can even create a persistent View that sorts it that way for your convenience.

Update the first and last records only amongst many duplicate records

I have a table in Access named Spells which holds patient spells (where a patient has a spell within a hospital). It's structure is as below:
| ID | SpellID | MultipleSpell | FirstSpell | LastSpell |
|----|---------|---------------|------------|-----------|
| 1 | 1 | False | | |
| 2 | 2 | True | | |
| 3 | 2 | True | | |
| 4 | 3 | False | | |
| 5 | 4 | False | | |
| 6 | 5 | True | | |
| 7 | 5 | True | | |
| 8 | 5 | True | | |
The MultipleSpell column indicates that there are multiple occurrences of the spell within the table.
I'd like to run query which would update the FirstSpell column to True for records with the IDs of 1,2,4,5,6. So basically, where a Spell is the first one in the table, it should be marked, in the FirstSpell column.
I would also then like to update the LastSpell column to True for records with the IDs of 1,3,4,5,8.
The reasoning for this (if you're interested) is that the table links to a separate table containing the name of wards. It would be useful to link to this other table and indicate whether the ward is the admitting ward (FirstSpell) or the discharging ward (LastSpell)
You can update the first using:
update spells
set firstspell = 1
where id = (select min(id)
from spells as s2
where spells.spellid = s2.spellid
);
Similar logic (using max()) can be used for the last spell.

SQL - Combining 3 rows per group in a logging scenario

I have reworked our API's logging system to use Azure Table Storage from using SQL storage for cost and performance reasons. I am now migrating our legacy logs to the new system. I am building a SQL query per table that will map the old fields to the new ones, with the intention of exporting to CSV then importing into Azure.
So far, so good. However, one artifact of the previous system is that it logged 3 times per request - call begin, call response and call end - and the new one logs the call as just one log (again, for cost and performance reasons).
Some fields common are common to all three related logs, e.g. the Session which uniquely identifies the call.
Some fields I only want the first log's value, e.g. Date which may be a few seconds different in the second and third log.
Some fields are shared for the three different purposes, e.g. Parameters gives the Input Model for Call Begin, Output Model for Call Response, and HTTP response (e.g. OK) for Call End.
Some fields are unused for two of the purposes, e.g. ExecutionTime is -1 for Call Begin and Call Response, and a value in ms for Call End.
How can I "roll up" the sets of 3 rows into one row per set? I have tried using DISTINCT and GROUP BY, but the fact that some of the information collides is making it very difficult. I apologize that my SQL isn't really good enough to really explain what I'm asking for - so perhaps an example will make it clearer:
Example of what I have:
SQL:
SELECT * FROM [dbo].[Log]
Results:
+---------+---------------------+-------+------------+---------------+---------------+-----------------+--+
| Session | Date | Level | Context | Message | ExecutionTime | Parameters | |
+---------+---------------------+-------+------------+---------------+---------------+-----------------+--+
| 84248B7 | 2014-07-20 19:16:15 | INFO | GET v1/abc | Call Begin | -1 | {"Input":"xx"} | |
| 84248B7 | 2014-07-20 19:16:15 | INFO | GET v1/abc | Call Response | -1 | {"Output":"yy"} | |
| 84248B7 | 2014-07-20 19:16:15 | INFO | GET v1/abc | Call End | 123 | OK | |
| F76BCBB | 2014-07-20 19:16:17 | ERROR | GET v1/def | Call Begin | -1 | {"Input":"ww"} | |
| F76BCBB | 2014-07-20 19:16:18 | ERROR | GET v1/def | Call Response | -1 | {"Output":"vv"} | |
| F76BCBB | 2014-07-20 19:16:18 | ERROR | GET v1/def | Call End | 456 | BadRequest | |
+---------+---------------------+-------+------------+---------------+---------------+-----------------+--+
Example of what I want:
SQL:
[Need to write this query]
Results:
+---------------------+-------+------------+----------+---------------+----------------+-----------------+--------------+
| Date | Level | Context | Message | ExecutionTime | InputModel | OutputModel | HttpResponse |
+---------------------+-------+------------+----------+---------------+----------------+-----------------+--------------+
| 2014-07-20 19:16:15 | INFO | GET v1/abc | Api Call | 123 | {"Input":"xx"} | {"Output":"yy"} | OK |
| 2014-07-20 19:16:17 | ERROR | GET v1/def | Api Call | 456 | {"Input":"ww"} | {"Output":"vv"} | BadRequest |
+---------------------+-------+------------+----------+---------------+----------------+-----------------+--------------+
select L1.Session, L1.Date, L1.Level, L1.Context, 'Api Call' AS Message,
L3.ExecutionTime,
L1.Parameters as InputModel,
L2.Parameters as OutputModel,
L3.Parameters as HttpResponse
from Log L1
inner join Log L2 ON L1.Session = L2.Session
inner join Log L3 ON L1.Session = L3.Session
where L1.Message = 'Call Begin'
and L2.Message = 'Call Response'
and L3.Message = 'Call End'
This would work in your sample.