Updating one column based on the value of another column - sql

I have a table named Vendor, within this table I have a column called AccountTerms which is shows only a value (i.e. 0, 1, 2, 3) and so on. I also have a column that I want to use (ulARAgeing) in order to reflect the meaning of that value, such as:
0: Current
1: 30 Days
2: 60 Days
and so on...
What I need is a script that will look at the value in AccountTerms and will then update ulARAgeing to show the word value shown above. How do I do this?

I am going to try to explain this in a simple manner as much as possible so it's easy to understand :
Let's assume, you have a table Vendor setup something like this:
create table Vendor (AccountTerms int, ulARAgeing varchar(50));
And, then we will insert some sample values for both columns in Vendor table:
insert into Vendor values
(0,'Test'),
(1,'Test1'),
(2,'Test2');
Next, we will write an update statement to update your ulARAgeing column based on the values in AccountTerms column in the same table:
update vendor
set ulARAgeing = (CASE
WHEN AccountTerms = 0
THEN 'Current'
WHEN AccountTerms = 1
THEN '30 Days'
WHEN AccountTerms = 2
THEN '60 Days'
END);
CASE WHEN is similar to using IF..ELSE statement in most other programming languages. So, here we will be updating the existing ulARAgeing value to different string value based on the condition in the case when statement. So, for e.g. if the AccountTerms = 0 then we will update the value for ulARAgeing to `Current' and so forth.
To check if the above statement worked correctly, you just need to run the update statement above and then select from the table again:
select * from Vendor;
Result:
+--------------+-----------------+
| AccountTerms | ulARAgeing |
+--------------+-----------------+
| 0 | Current |
| 1 | 30 Days |
| 2 | 60 Days |
+--------------+-----------------+
SQL Fiddle Demo

Assuming you want a simple script to update, then it would be like this:
update
Vendor
set ulARAgeing = 'Current'
where AccountTerms = 0;
Assuming you want a script where it automatically update the column from a logic of numeric progression. Then it would be like this:
;WITH CTE
AS (select
AccountTerms
,ulARAgeing
,CONCAT((AccountTerms * 30), ' Days') as _ulARAgeing
from
Vendor)
UPDATE CTE
SET ulARAgeing = _ulARAgeing;
If by chance the value of "ulARAgeing" come from another table, then the script using "; WITH", you must use a join to get the correct value, instead of using a logic of progression.

Related

How to set flag based on values in previous columns in same table ? (Oracle)

I'm creating a new table and carrying over several columns from a previous table. One of the new fields that I need to create is a flag that will have values 0 or 1 and value needs to be determined based on 6 previous fields in the table.
The 6 previous columns have preexisting values of 0 or 1 stored for each one. This new field needs to check whether any of the 6 columns have 1 and if so set the flag to 0. If there is 0 in all 6 fields then set itself to 1.
Hopefully this makes sense. How can I get this done in oracle? I assume a case statement and some sort of forloop?
You can use greatest() function: GREATEST
create table t_new
as
select
case when greatest(c1,c2,c3,c4,c5,c6)=1 -- at least one of them contains 1
then 0
else 1
end c_new
from t_old;
Or even shorter:
create table t_new
as
select
1-greatest(c1,c2,c3,c4,c5,c6) as c_new
from t_old;
In case of greatest = 1, (1-1)=0, otherwise (1-0)=1
You can use a virtual column with a case expression; something like:
flag number generated always as (
case when val_1 + val_2 + val_3 + val_4 + val_5 + val_6 = 0 then 1 else 0 end
) virtual
db<>fiddle
or the same thing with greatest() as #Sayan suggested.
Using a virtual column means the flag will be right for newly-inserted rows, and if any of the other values are updated; you won't have to recalculate or update the flag column manually.
I've assumed the other six columns can't be null and are constrained to only be 0 or 1, as the question suggests. If they can be null you can add nvl() or coalesce() to each term in the calculation.

Updating a value in one row where is currently null ,where in other row there is data

I'm working to reconsile or AWS bill in our cost reporting tool we're built and I need some guidence on how to execute this type of update in Postgres.
The AWS bill is in the Table 'BillingData' and every row is the cost billing per 'ResourceId' every hour.
For example, we have
ResourceId|BlendedCost|user:Product|UsageStartDate
i-34r8uefg | 0.8763 |<null>|04-01-01 01:00
i-34r8uefg | 0.8763 |AwesomeProductTag|04-01-01 02:00
This shows that at hour 01 the instance was not tagged, but on hour 02 it was. We have 1,000s of rows like this.
What I would like to do is wherever there's a row that has NULL data for column "user:Product", populate that column with data that is elsewhere in that table, for the same "ResourceId".
In more clear terms, someone when they created 'i-34r8uefg' did not tag it properly, but did so later on. I have the following query which gives me rows where instances are not tagged at one hour, but tagged at a different hour
select "ResourceId","user:Product" from billingdata
where "user:Product" NOTNULL
and "ResourceId" in
(select DISTINCT "ResourceId"
from billingdata
where "user:Product" ISNULL);
I want to set the "user:Product" where it is null at one hour(row), to the value that exists later on in the table.
Assuming your requirements are:
Two rows must have the same ResourceId
The target row must have a null user:Product
The source tow must have a non-null user:Product
The source row must be entered after the target row
...then you can use this:
UPDATE "BillingData" AS "Target" SET
"user:Product" = "Source"."user:Product"
FROM "BillingData" AS "Source"
WHERE "Source"."ResourceId" = "Target"."ResourceId"
AND "Target"."user:Product" IS NULL
AND "Source"."user:Product" IS NOT NULL
AND "Target"."UsageStartDate" < "Source"."UsageStartDate"
;
Note that if you have two source rows with the same ResourceId but different non-null user:Product values then it will be a crapshoot as to which row is used as the source for the update. You should check the uniqueness of source rows beforehand using a query like this:
SELECT
"ResourceId"
FROM "BillingData"
WHERE "user:Product" IS NOT NULL
GROUP BY "ResourceId"
HAVING COUNT(*) > 1
...or alternately, use this as a filter predicate in your query to avoid the problem (but not fully solve your original problem), like so:
UPDATE "BillingData" AS "Target" SET
"user:Product" = "Source"."user:Product"
FROM "BillingData" AS "Source"
WHERE "Source"."ResourceId" = "Target"."ResourceId"
AND "Target"."user:Product" IS NULL
AND "Source"."user:Product" IS NOT NULL
AND "Target"."UsageStartDate" < "Source"."UsageStartDate"
AND NOT EXISTS (
SELECT *
FROM "BillingData"
WHERE "user:Product" IS NOT NULL
AND "ResourceId" = "Source"."ResourceId"
HAVING COUNT(*) > 1
)
;

SQL query for two values of one row based off same table column

I have two columns of one row of a report that I would like to be based off the same one column in a SQL table.
For example, in the report it should be something like:
ID | Reason | SubReason
1 | Did not like | Appearance
In the SQL table it is something like:
ID | ReturnReason
1 | Did not like
1 | XX*SR*Appearance
1 | XX - TestData
1 | XX - TestData2
The SubReason column is being newly added and the current SQL query is something like:
SELECT ID, ReturnReason AS 'Reason'
FROM table
WHERE LEFT(ReturnReason,2) NOT IN ('XX')
And now I'd like to add a column in the SELECT statement for SubReason, which should be the value if *SR* is in the value. This however won't work because it also has 'XX' in the value, which is omitted by the current WHERE clause.
SELECT t.ID, t.ReturnReason AS 'Reason',
SUBSTRING(t1.ReturnReason,7,10000) as 'SubReason '
FROM t
LEFT JOIN t as t1 on t.id=t1.id and t1.ReturnReason LIKE 'XX*SR*%'
WHERE t.ReturnReason NOT LIKE 'XX%'
SQLFiddle demo

SQL Query to remove cyclic redundancy

I have a table that looks like this:
Column A | Column B | Counter
---------------------------------------------
A | B | 53
B | C | 23
A | D | 11
C | B | 22
I need to remove the last row because it's cyclic to the second row. Can't seem to figure out how to do it.
EDIT
There is an indexed date field. This is for Sankey diagram. The data in the sample table is actually the result of a query. The underlying table has:
date | source node | target node | path count
The query to build the table is:
SELECT source_node, target_node, COUNT(1)
FROM sankey_table
WHERE TO_CHAR(data_date, 'yyyy-mm-dd')='2013-08-19'
GROUP BY source_node, target_node
In the sample, the last row C to B is going backwards and I need to ignore it or the Sankey won't display. I need to only show forward path.
Removing all edges from your graph where the tuple (source_node, target_node) is not ordered alphabetically and the symmetric row exists should give you what you want:
DELETE
FROM sankey_table t1
WHERE source_node > target_node
AND EXISTS (
SELECT NULL from sankey_table t2
WHERE t2.source_node = t1.target_node
AND t2.target_node = t1.source_node)
If you don't want to DELETE them, just use this WHERE clause in your query for generating the input for the diagram.
If you can adjust how your table is populated, you can change the query you're using to only retrieve the values for the first direction (for that date) in the first place, with a little bit an analytic manipulation:
SELECT source_node, target_node, counter FROM (
SELECT source_node,
target_node,
COUNT(*) OVER (PARTITION BY source_node, target_node) AS counter,
RANK () OVER (PARTITION BY GREATEST(source_node, target_node),
LEAST(source_node, target_node), TRUNC(data_date)
ORDER BY data_date) AS rnk
FROM sankey_table
WHERE TO_CHAR(data_date, 'yyyy-mm-dd')='2013-08-19'
)
WHERE rnk = 1;
The inner query gets the same data you collect now but adds a ranking column, which will be 1 for the first row for any source/target pair in any order for a given day. The outer query then just ignores everything else.
This might be a candidate for a materialised view if you're truncating and repopulating it daily.
If you can't change your intermediate table but can still see the underlying table you could join back to it using the same kind of idea; assuming the table you're querying from is called sankey_agg_table:
SELECT sat.source_node, sat.target_node, sat.counter
FROM sankey_agg_table sat
JOIN (SELECT source_node, target_node,
RANK () OVER (PARTITION BY GREATEST(source_node, target_node),
LEAST(source_node, target_node), TRUNC(data_date)
ORDER BY data_date) AS rnk
FROM sankey_table) st
ON st.source_node = sat.source_node
AND st.target_node = sat.target_node
AND st.rnk = 1;
SQL Fiddle demos.
DELETE FROM yourTable
where [Column A]='C'
given that these are all your rows
EDIT
I would recommend that you clean up your source data if you can, i.e. delete the rows that you call backwards, if those rows are incorrect as you state in your comments.

How do I specify a default value in a MS Access query?

I have three tables similar to the following:
tblInvoices: Number | Date | Customer
tblInvDetails: Invoice | Quantity | Rate | Description
tblPayments: Invoice | Date | Amount
I have created a query called exInvDetails that adds an Amount column to tblInvDetails:
SELECT tblInvDetails.*, [tblInvDetails.Quantity]*[tblInvDetails.Rate]* AS Amount
FROM tblInvDetails;
I then created a query exInvoices to add Total and Balance columns to tblInvoices:
SELECT tblInvoices.*,
(SELECT Sum(exInvDetails.Amount) FROM exInvDetails WHERE exInvDetails.Invoice = tblInvoices.Number) AS Total,
(SELECT Sum(tblPayments.Amount) FROM tblPayments WHERE tblPayments.Invoice = tblInvoices.Number) AS Payments,
(Total-Payments) AS Balance
FROM tblInvoices;
If there are no corresponding payments in tblPayments, the fields are null instead of 0. Is there a way to force the resulting query to put a 0 in this column?
Use the nz() function, as in nz(colName, 0). This will return colName, unless it is null, in which case it will return the 2nd paramter (in this case, 0).
I think that Default Value likes Field location. For example, My Field is ID that is in tblEmpPCs table, I used a criteria below.
IIf([Forms]![frmSearchByEmp]![cboTurul]="ID",[forms]![frmSearchByEmp]![Ezemshigch],[tblEmpPCs].[ID])
There are False value is Default value of Criteria.
I uploaded a picture of my query criteria. It may help you.