Merge on multiple conditions - sql

Is it possible to use multiple conditions on SQL merge ON condition to make as unique identifier instead of concatenating?
CompanyId+StoreLocation = UniqueId. I do not want to create an additional concatenated column. Will this work? If not, what could be the best solution?
ON (target.CompanyId = source.CompanyId AND target.Storelocation = source.storelocation)
CompanyId StoreLocation StoreSQM
------------------------------------
12345 Chicago01 1650
12345 Chicago02 1985
12652 Milwaukee 1865
45846 Minneapolis 45845
MERGE dbo.storestbl AS target
USING stagingtbl AS source
**ON (target.CompanyId = source.CompanyId AND target.Storelocation = source.storelocation)**
WHEN MATCHED THEN
Do something
WHEN NOT MATCHED THEN
Do something

Related

Join and aggregating two internal tables into one

I need to aggregate the below two tables into one, per True_Origin and True_Destination level.
Table 2 (IT_DATES_OD):
FDate2 Flight_Number2 Origin2 Destination2 Amount3 Amount4
20190501 123 DXB LOS 5 12
20190501 123 DXB LOS 22 558
20190501 123 DXB LOS 2556 4585
Table 1 (IT_TOD_OD):
Flight_Date_OD Flight_Number_OD Origin Destination True_origin True_destination Net_Net_Net Amount2
20190501 123 DXB LOS DXB NBO 5 12
20190501 123 DXB LOS DXB ADD 22 558
20190501 123 DXB LOS DXB LOL 2556 4585
I can aggregate using common fields (Date, Flight Number, Origin, Destination) but I can't aggregate on a detailed level on True_origin and True_destination.
SORT IT_DATES_TOD BY FDATE2 FLIGHT_NUMBER2 ORIGIN2 DESTINATION2 ASCENDING.
CLEAR WA_OUTPUT.
LOOP AT IT_DATES_TOD INTO WA_DATES_TOD WHERE FDATE2 <> ''.
WA_OUTPUT-FDATE = WA_DATES_TOD-FDATE2.
WA_OUTPUT-FLIGHT_NUMBER = WA_DATES_TOD-FLIGHT_NUMBER2.
WA_OUTPUT-ORIGIN = WA_DATES_TOD-ORIGIN2.
WA_OUTPUT-DESTINATION = WA_DATES_TOD-DESTINATION2.
LOOP AT IT_TOD_OD INTO WA_TOD_OD
WHERE FLIGHT_DATE_OD = WA_DATES_TOD-FDATE2
AND FLIGHT_NUMBER_OD = WA_DATES_TOD-FLIGHT_NUMBER2
AND ORIGIN = WA_DATES_TOD-ORIGIN2
AND DESTINATION = WA_DATES_TOD-DESTINATION2.
WA_OUTPUT-TRUE_ORIGIN = WA_TOD_OD-TRUE_ORIGIN.
WA_OUTPUT-TRUE_DESTINATION = WA_TOD_OD-TRUE_DESTINATION.
WA_OUTPUT-NET_NET_NET = WA_TOD_OD-NET_NET_NET.
WA_OUTPUT-RE_PRO_REVFUEL = 0.
WA_OUTPUT-BLOCK_HOUR = 0.
APPEND WA_OUTPUT TO IT_OUTPUT.
ENDLOOP.
ENDLOOP.
Please have a look at the collect Syntax in ABAP:
COLLECT statement in ABAP is used for inserting the components of a work area into an internal table by avoiding duplicate entries and also in a summarized way.
Syntax
COLLECT <line> INTO <itab>
When you use collect statement the following steps are occurring.
First it will check in internal table for any record matching with the key in work area data.
If it couldn’t find any matching record, then the new data from work area will be inserted in internal table
If any record found with the same key, then instead of inserting a new record, it will add the numeric field values of work area components with the corresponding field components in the matched record and update the internal table record.
both of your itabs should use the Destination structure:
Date F_Number Orign Destin T_origin T_destin Amount Amount2
so the collect command can make use add functionality of the numeric fields.

Comparing 2 tables in rails 5

I have 2 tables "existing_practices" & "latest_practices", both contain a column "practice_id"
What I want to do is compare latest_practices with the existing_practices to find which practices are on the latest_practices table that I don't have on my existing_practices (in other words I need to find the new practices)
Example:
existing_practices latest_practices
------------------ ------------------
practice_id practice_id
A123 A123
B123 B123
C123 C123
D123
So given the 2 above tables I would need to identify that "D123" is a new practice.
I have tried the following but it doesn't seem to work:
existing_practices = ExistingPractice.select(:practice_id).all
latest_practices = LatestPractice.select(:practice_id).all
new_practices = latest_practices.to_a - existing_practices.to_a
I'm thinking the easiest way is to just write the raw sql but i want to do it the rails way (if there is one).
Can anyone help?
pluck used to fetch column value as array
new_practices = LatestPractice.pluck(:practice_id) - ExistingPractice.pluck(:practice_id)
You can use sql directly for better performance.
new_practices_id = ActiveRecord::Base.connection.execute("SELECT DISTINCT latest_practices.practice_id FROM latest_practices LEFT JOIN existing_practices ON latest_practices.practice_id =
existing_practices.practice_id WHERE existing_practices.practice_id IS NULL")
This will return an array of the practice_id that doesn't exist at the existing_practices table.
here is the fiddle example company two columns or tables
you can do it like this with pluck
new_practices = LatestPractice.pluck(:practice_id) - ExistingPractice.pluck(:practice_id)
If you have a lot of data the solution of plucking practice_id and subtracting them is poorly performing. Instead I suggest:
Okish:
LatestPractice.where.not(practice_id: ExistingPractice.all)
better:
LatestPractice.where.not("EXISTS(SELECT 1 from existing_practices where latest_practices.practice_id = existing_practices.practice_id)")
much better:
LatestPractice.where('practice_id NOT IN(SELECT DISTINCT(practice_id) FROM existing_practices)')

How to add an increasing var +1 if field.tab1=field.tab2 in sql

If anyone can help
I have two tables like this:
field.tab1
111
1110
1111
1112
field.tab2
111
I need to update table 2 like this:
field.tab2
1113
Thank you for your quick response and guidance
Yes I'm new here and in sql, access too, I have those two tables that i need to compare and make the field from second table to have unique records because will be appended to the first table, so this is what i've done in access:
SELECT tab2.field, tab1.field, tab1.field1, tab2.field1
FROM tab2 LEFT JOIN tab1 ON tab2.field=tab1.field;
and manualy increase every tab1.field :) until tab2.field and tab2.field1 become null, where field is the number of client and field1 number of order.
The natural answer to this question is:
update field.tab2
set col = 1113
where col = 111;

Postgres update with an inner join across 3 tables?

This morning I asked this very similar question, and it was answered beautifully.
However, after reviewing the play, I see that my actual problem is slightly more complicated than what I described in that question. Basically, I have 3 Postgres tables:
[myschema].[animals]
--------------------
animal_id
animal_attrib_type_id (foreign key to [myschema].[animal_attrib_types])
animal_attrib_value_id (foreign key to [myschema].[animal_attrib_values])
[myschema].[animal_attrib_types]
--------------------------------
animal_attrib_type_id
animal_attrib_type_name
[myschema].[animal_attrib_values]
--------------------------------
animal_attrib_value_id
animal_attrib_value_name
So, I might have an animal record like so:
[myschema].[animals]
--------------------
animal_id = 458
animal_attrib_type_id = 38
animal_attrib_value_id = 23
And the corresponding animal_attrib_type (with id = 38) has the following values:
[myschema].[animal_attrib_types]
--------------------------------
animal_attrib_type_id = 38
animal_attrib_type_name = 'animals.should-make-noise'
And the corresponding animal_attrib_value (with id = 23) has the following values:
[myschema].[animal_attrib_values]
--------------------------------
animal_attrib_type_id = 23
animal_attrib_type_name = 'true'
So, the same animal record can have multiple type/value pairs. In this case the animal had an animal_attrib_type_name of "animals.should-make-noise" corresponding to an animal_attrib_value_name of "true".
At runtime, I will only have the animal_id (i.e, 458) and animal_attrib_type_id (i.e, 38). I need to be able to look up the appropriate animal_attrib_value_name corresponding to that given animal_id and animal_attrib_type_id only, and then update its value to some static text ('true' or 'false'); all from within the same UPDATE statement.
The answer in the above-referenced question was correct for the problem I stated, but since the same animal has 0+ type/value combos I actually need a slightly different SQL statement. Thanks in advance!
Make use of the FROM clause in the PostgreSQL UPDATE command. This is usually cleaner and faster.
UPDATE animal_attrib_values av
SET animal_attrib_value_name = 'true'
FROM animals a
WHERE a.animal_id = 458
AND a.animal_attrib_type_id = 38
AND a.animal_attrib_value_id = av.animal_attrib_value_id;
Since we already know the animal_attrib_type_id we don't have to include the third table animal_attrib_types at all. We could join to it additionally if needed ...
Also, do not table-qualify SET items in an UPDATE. That's a syntax error. I quote the manual on said page:
Do not include the table's name in the specification of a target
column — for example, UPDATE tab SET tab.col = 1 is invalid.
Bold emphasis mine.
The below SQL should do what you are asking:
UPDATE animal_attrib_values aav
SET animal_attrib_value_name= 'true'
WHERE aav.animal_attrib_value_id = (
SELECT a.animal_attrib_value_id
FROM animals a
WHERE a.animal_id = 458
AND a.animal_attrib_type_id = 38
)
;

SQL Server - copy data across tables , but copy the data only when it match with a specific column name

For example I got this 2 table
dbo.fc_states
StateId Name
6316 Alberta
6317 British Columbia
and dbo.fc_Query
Name StatesName StateId
Abbotsford Quebec NULL
Abee Alberta NULL
100 Mile House British Columbia NULL
Ok pretty straightforward , how do I copy the stateId over from fc_states to fc_Query, but match it with the StatesName, let say the result would be
Name StatesName StateId
Abee Alberta 6316
100 Mile House British Columbia 6317
Thanks, and both stateName column type is text
How about:
update fc_Query set StateId =
(select StateId from fc_states where fc_states.Name = fc_Query.StatesName)
That should give you the result you're looking for.
This is a different way than what Eddie did, I like MERGE for updates if they're not dead simple (like I wouldn't consider yours dead simple). So if you're bored/curious also try
WITH stateIds as
(SELECT name, MAX(stateID) as stID
FROM fc_states
GROUP BY name)
MERGE fc_Query
on stateids.name = fc_query.statesname
WHEN MATCHED THEN UPDATE
SET fc_query.stateid = convert(int, stid)
;
The first part, from "WITH" to the GROUP BY NAME), is a CTE, that creates a table-like thing - a name 'stateIds' that is good as a table for the immediately following part of the query - where there's guaranteed to be only one row per state name. Then the MERGE looks for anything in the fc_query with a matching name. And if there's a match, it sets it as you want. YOu can make a small edit if you don't want to overwrite existing stateids in fc_query:
WITH stateIds as
(SELECT name, MAX(stateID) as stID
FROM fc_states
GROUP BY name)
MERGE fc_Query
ON stateids.name = fc_query.statesname
AND fc_query.statid IS NOT NULL
WHEN MATCHED THEN UPDATE
SET fc_query.stateid = convert(int, stid)
;
And you can have it do something different to rows that don't match. So I think MERGE is good for a lot of applications. You need a semicolon at the end of MERGE statements, and you have to guarantee that there will only be one match or zero matches in the source (that is "stateids", my CTE) for each row in the target; if there's more than one match some horrible thing happens, Satan wins or the US economy falters, I'm not sure what, just never let it happen.