Copy fields from one column to another with criteria - sql

I have a table called 02_Month with the following information:
|------------------------------------------------------------------
| Soc | Society | USD_STD | USD_STD_R |
|------------------------------------------------------------------|
| AB02 | Plants | 3.8 | 1 |
| JK01 | Trees | 2.4 | 1 |
| WB09 | Bushes | 1.2 | 3 |
| COIN | Flowers | 4.6 | 2 |
| KK99 | Stones | 66.9 | 3 |
| TCTC | Ruby | 19.0 | 5 |
| WNOL | Steel | 71.1 | 7 |
|------------------------------------------------------------------
I want to copy what says in column USD_STD to USD_STD_R if the column Soc is COIN or TCTC. I want to have this at the end:
|------------------------------------------------------------------
| Soc | Society | USD_STD | USD_STD_R |
|------------------------------------------------------------------|
| AB02 | Plants | 3.8 | 1 |
| JK01 | Trees | 2.4 | 1 |
| WB09 | Bushes | 1.2 | 3 |
| COIN | Flowers | 4.6 | 4.6 |
| KK99 | Stones | 66.9 | 3 |
| TCTC | Ruby | 19.0 | 19.0 |
| WNOL | Steel | 71.1 | 7 |
|------------------------------------------------------------------
I wrote this:
UPDATE 02_Month
SET [02_Month].USD_STD_R = USD_STD
WHERE (([02_Month].Soc="COIN") or ([02_Month].Soc="TCTC"));
It is not working as expected. I suppose it's due to the WHERE condition. if I don't write that line it copies the entire column USD_STD in USD_STD_R.
The code I wrote prints 0 in all of the fields of USD_STD_R. Why doesn't it work and how can it be corrected?

The following should be sufficient:
update [02_month] t
set t.usd_std_r = t.usd_std
where t.soc="COIN" or t.soc="TCTC"
A few notes:
Since your table name starts with a number, it must be enclosed in square brackets.
The use of t is merely an alias to avoid the need to repeatedly write [02_month]
You can use either t.soc="COIN" or t.soc="TCTC" or t.soc in ("COIN","TCTC") both should yield the same result.
Double-quotes " are typically used by MS Access, but single-quotes ' should also be valid.

USD_STD instead of STD_USD
Also you can use IN operator
UPDATE 02_Month
SET [02_Month].USD_STD_R = USD_STD
FROM [02_Month]
WHERE ([02_Month].Soc IN ('COIN','TCTC'));

Please, try with below query. string value always within ''.
UPDATE 02_Month
SET USD_STD_R = USD_STD
WHERE Soc in ('COIN','TCTC');

your relation 02_month with column field USD_STD USD_STD_R but in update statement column field name is STD_USD_R and STD_USD.

You can use inner join update as shown below.
UPDATE a
SET a.USD_STD_R = b.USD_STD --You can change another column here as per your need.
FROM [02_Month] a
INNER JOIN [02_Month] b ON a.soc = b.soc
AND a.society = b.society
AND a.USD_STD = b.USD_STD
AND a.USD_STD_R = b.USD_STD_R
WHERE a.Soc in ('COIN','TCTC');
Live Demo Here
If you do not want alias name for updating table.
UPDATE [02_Month]
SET [02_Month].USD_STD_R = b.USD_STD --You can change another column here as per your need.
FROM [02_Month]
INNER JOIN [02_Month] b ON [02_Month].soc = b.soc
AND [02_Month].society = b.society
AND [02_Month].USD_STD = b.USD_STD
AND [02_Month].USD_STD_R = b.USD_STD_R
WHERE [02_Month].Soc in ('COIN','TCTC');
db<>fiddle Demo

Related

How to update column in table from two different tables USING DML Command

I have three different tables here:
df_umts_relation table:
|---------------------|------------------|---------------------|------------------|------------------|
| cell_name | n_cell_name | technology | source_ops_num | target_ops_num |
|---------------------|------------------|---------------------|------------------|------------------|
| 121 | 221 | UMTS | 1 | | |
|---------------------|------------------|---------------------|------------------|------------------|
| 122 | 222 | GSM | 2 | | |
|---------------------|------------------|---------------------|------------------|------------------|
| 123 | 223 | UMTS | 3 | | |
|---------------------|------------------|---------------------|------------------|------------------|
| 124 | 224 | GSM | 4 | | |
|---------------------|------------------|---------------------|------------------|------------------|
| 125 | 225 | GSM | 5 | | |
|---------------------|------------------|---------------------|------------------|------------------|
| 126 | 226 | UMTS | 6 | | |
|---------------------|------------------|---------------------|------------------|------------------|
| 127 | 227 | UMTS | 7 | | |
|---------------------|------------------|---------------------|------------------|------------------|
So now I want to update target_ops_num from the two below tables
df_umts_carrier table as this table contains those thow columns I want to work on them and contains some integer values also:
|---------------------|------------------|
| opsnum_umts | cell_name_umts |
|---------------------|------------------|
as I have another table called df_gsm_carrier:
|---------------------|------------------|
| opsnum_gsm | cellname |
|---------------------|------------------|
So All I need I want to update [MyNewDatabase].[dbo].[df_umts_relation].[target_ops_num] CASE WHEN technologyis UMTS then update from table df_umts_carrier ELSE technology is GSM then update from df_gsm_carrier on n_cell_name = cell_name_umts and on n_cell_name = cellname
So I tried to create a query as the below one works with one condition only and it's update the the rows which is UMTS only:
UPDATE [MyNewDatabase].[dbo].[df_umts_relation]
SET [MyNewDatabase].[dbo].[df_umts_relation].[target_ops_num] = [MyNewDatabase].[dbo].[df_umts_carrier].[opsnum_umts]
FROM [MyNewDatabase].[dbo].[df_umts_relation]
INNER JOIN [MyNewDatabase].[dbo].[df_umts_carrier]
ON [n_cell_name] = [cell_name_umts]
and works fine but doesn't update the rows which contains GSM...
On other way I tried to create a query to handle this but it didn't update the GSM part and take a long of time:
UPDATE [MyNewDatabase].[dbo].[df_umts_relation]
SET [MyNewDatabase].[dbo].[df_umts_relation].[target_ops_num] = (CASE WHEN [MyNewDatabase].[dbo].[df_umts_relation].[technology] = 'UMTS'
THEN [MyNewDatabase].[dbo].[df_umts_carrier].[opsnum_umts] ELSE [MyNewDatabase].[dbo].[df_gsm_carrier].[opsnum_gsm] END)
FROM [MyNewDatabase].[dbo].[df_umts_relation]
LEFT JOIN [MyNewDatabase].[dbo].[df_umts_carrier]
ON [n_cell_name] = [cell_name_umts]
LEFT JOIN [MyNewDatabase].[dbo].[df_gsm_carrier]
ON [n_cell_name] = [cell_name]
So any one have any idea how to solve this?
Please check if this will help.
update df_umts_relation
set target_ops_num = ( select case when dur.technology = 'UMTS' then du.cell_name_umts
when dur.technology = 'GSM' then dg.cellname
end
from df_umts_relation dur
left join df_umts_carrier du on dur.n_cell_name = du.opsnum_umts
left join df_gsm_carrier dg on dur.n_cell_name = dg.opsnum_umts
where dur.id= df_umts_relation.id)
Here is a demo

When Querying Many-To-Many Relationship in SQL, Return Multiple Connections As an Array In Single Row?

Basically, I have 3 tables, titles, providers, and provider_titles.
Let's say they look like this:
| title_id | title_name |
|------------|----------------|
| 1 | San Andres |
| 2 |Human Centipede |
| 3 | Zoolander 2 |
| 4 | Hot Pursuit |
| provider_id| provider_name |
|------------|----------------|
| 1 | Hulu |
| 2 | Netflix |
| 3 | Amazon_Prime |
| 4 | HBO_GO |
| provider_id| title_id |
|------------|----------------|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
| 3 | 3 |
| 4 | 4 |
So, clearly there are titles with multiple providers, yeah? Typical many-to-many so far.
So what I'm doing to query it is with a JOIN like the following:
SELECT * FROM provider_title JOIN provider ON provider_title.provider_id = provider.provider_id JOIN title ON title.title_id = provider_title.title_id WHERE provider.name IN ('Netflix', 'HBO_GO', 'Hulu', 'Amazon_Prime')
Ok, now to the actual issue. I don't want repeated title names back, but I do want all of the providers associated with the title. Let me explain with another table. Here is what I am getting back with the current query, as is:
| provider_id| provider_name | title_id | title_name |
|------------|---------------|----------|---------------|
| 1 | Hulu | 1|San Andreas |
| 1 | Hulu | 2|Human Centipede|
| 2 | Netflix | 1|San Andreas |
| 3 | Amazon_Prime | 1|San Andreas |
| 3 | Amazon_prime | 3|Zoolander 2 |
| 4 | HBO_GO | 4|Hot Pursuit |
But what I really want would be something more like
| provider_id| provider_name |title_id| title_name|
|------------|-----------------------------|--------|-----------|
| [1, 2, 3] |[Hulu, Netflix, Amazon_Prime]| 1|San Andreas|
Meaning I only want distinct titles back, but I still want each title's associated providers. Is this only possible to do post-sql query with logic iterating through the returned rows?
Depending on your database engine, there may be an aggregation function to help achieve this.
For example, this SQLfiddle demonstrates the postgres array_agg function:
SELECT t.title_id,
t.title_name,
array_agg( p.provider_id ),
array_agg( p.provider_name )
FROM provider_title as pt
JOIN
provider as p
ON pt.provider_id = p.provider_id
JOIN title as t
ON t.title_id = pt.title_id
GROUP BY t.title_id,
t.title_name
Other database engines have equivalents. For example:
mySQL has group_concat
Oracle has listagg
sqlite has group_concat (as well!)
If your database isn't covered by the above, you can google '[Your database engine] aggregate comma delimited string'

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 query for many-to-many self-join

I have a database table that has a companion many-to-many self-join table alongside it. The primary table is part and the other table is alternate_part (basically, alternate parts are identical to their main part with different #s). Every record in the alternate_part table is also in the part table. To illustrate:
`part`
| part_id | part_number | description |
|---------|-------------|-------------|
| 1 | 00001 | wheel |
| 2 | 00002 | tire |
| 3 | 00003 | window |
| 4 | 00004 | seat |
| 5 | 00005 | wheel |
| 6 | 00006 | tire |
| 7 | 00007 | window |
| 8 | 00008 | seat |
| 9 | 00009 | wheel |
| 10 | 00010 | tire |
| 11 | 00011 | window |
| 12 | 00012 | seat |
`alternate_part`
| main_part_id | alt_part_id |
|--------------|-------------|
| 1 | 5 | // Wheel
| 5 | 1 | // |
| 5 | 9 | // |
| 9 | 5 | // |
| 2 | 6 | // Tire
| 6 | 2 | // |
| ... | ... | // |
I am trying to produce a simple SQL query that will give me a list of all alternates for a main part. The tricky part is: some alternates are only listed as alternates of alternates, it is not guaranteed that every viable alternate for a part is listed as a direct alternate. e.g., if 'Part 3' is an alternate of 'Part 2' which is an alternate of 'Part 1', then Part 3 is an alternate of Part 1 (even if the alternate_part table doesn't list a direct link). The reverse is also true (Part 1 is an alternate of Part 3).
Basically, right now I'm pulling alternates and iterating through them
SELECT p.*, ap.*
FROM part p
INNER JOIN alternate_part ap ON p.part_id = ap.main_part_id
And then going back and doing the same again on those alternates. But, I think there's got to be a better way.
The SQL query I'm looking for will basically give me:
| part_id | alt_part_id |
|---------|-------------|
| 1 | 5 |
| 1 | 9 |
For part_id = 1, even when 1 & 9 are not explicitly linked in the alternates table.
Note: I have no control whatever over the structure of the DB, it is a distributed software solution.
Note 2: It is an Oracle platform, if that affects syntax.
You have to create hierarchical tree , probably you have to use connect by prior , nocycle query
something like this
select distinct p.part_id,p.part_number,p.description,c.main_part_id
from part p
left join (
select main_part_id,connect_by_root(main_part_id) real_part_id
from alternate_part
connect by NOCYCLE prior main_part_id = alternate_part_id
) c
on p.part_id = c.real_part_id and p.part_id != c.main_part_id
order by p.part_id
You can read full documentation about Hierarchical queries at http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries003.htm

Grand Total value doesn't match with Top N Filtered values in SSRS

I have a report in reporting services. In this report, I am displaying the Top N values. But my Grand Total is displaying the sum of all the values.
Right now I am getting something like this.Here N = 2
+-------+------+-------------+
| Area |ID | Count |
+-------+------+-------------+
| - A | | 4 |
| | a1 | 1 |
| | b1 | 1 |
| | c1 | 1 |
| | d1 | 1 |
| | | |
| - B | | 3 |
| | a2 | 1 |
| | b2 | 1 |
| | c2 | 1 |
| | | |
|Grand | | 10 |
|Total | | |
+-------+------+-------------+
The correct Grand Total should be 7 instead of 10. A and B are toggle items(You can expand and contract)
How can I display the correct Grand Total using Top N filter?
I also want to use the filter in the report and not in the SQL query.
You should use the filter on the Dataset. Filtering the report object itself only turns off the items (rows, for example) visibility. The item / row itself will still be part of the group and will be used for calculations.
I found a way to solve my question. As Ido said I worked on the dataset. I am using Analysis Cube. So in this cube I created a Named Set Calculation.
In this set I used the TopCount() function. It filters out the TOP N values where N can be integer according to your choice.
So the final Named Set in this case is :-
TopCount([Dim Area].[Area].[Area], 2, ([Measures].[Count]))
This will give you Grand total of Top N filtered values.