Using MERGE in SQL Server 2008 - sql-server-2008

I just found out about this nifty little feature. I have a couple questions. consider the statement below.
This is how interpret how it works. The USING statement is what gets compared to see if there is a match correct? I want to use how it is now, but I want to use 2 other columns from the source table in the MATCH portion. I can't do that. So is there a way that I can use the 2 columns (decesed (I know its spelled wrong :) ) and hicno_enc)?
Another thing I would like to do and don't know if it possible, but if the row exists in target but not source, then mark it inactive.
SELECT FIRST_NAME, LAST_NAME, SEX1, BIRTH_DATE
FROM
aco.tmpimport i
INNER JOIN aco.patients p
ON p.hicnoenc = i.hicno_enc
MERGE aco.patients AS target
USING (
SELECT FIRST_NAME, LAST_NAME, SEX1, BIRTH_DATE
FROM aco.tmpimport
) AS source
ON target.hicnoenc = source.hicno_enc
WHEN MATCHED AND target.isdeceased <> CONVERT(BIT,source.decesed) THEN
UPDATE
SET
target.isdeceased = source.decesed,
updatedat = getdate(),
updatedby = 0
WHEN NOT MATCHED THEN
INSERT (firstname, lastname, gender, dob, isdeceased, hicnoenc)
VALUES (source.FIRST_NAME,
source.LAST_NAME,
source.sex1,
source.BIRTH_DATE,
source.decesed,
source.hicno_enc);

So is there a way that I can use the 2 columns (decesed (I know its
spelled wrong :) ) and hicno_enc)?
Add the columns you need in the select statement in the using clause.
USING (
SELECT FIRST_NAME, LAST_NAME, SEX1, BIRTH_DATE, decesed, hicno_enc
FROM aco.tmpimport
) AS source
if the row exists in target but not source, then mark it inactive.
Add a when not matched by source clause and do the update.
WHEN NOT MATCHED BY SOURCE THEN
UPDATE
SET active = 0

Related

How to minimize duplicate queries

Suppose I have two datasets.
In QlikView, if I try to include these in a load using a query like the following:
sql select marriage_id, primary_person_id, seconary_person_id, marriage_start_date, marriage_end_date from marriage_table;
sql select person_id as primary_person_id, person_id as seconary_person_id, first_name, middle_name, last_name, date_of_birth from person_table;
I will get an error about how I could be leading myself to have inaccurate data, as QlikView has two potential paths to get to PERSON_TABLE. Which makes sense, but I really really hate the idea of duplicating the selects and tables like the following.
sql select marriage_id, primary_person_id, seconary_person_id, marriage_start_date, marriage_end_date from marriage_table;
sql select person_id as primary_person_id, first_name, middle_name, last_name, date_of_birth from person_table;
sql select person_id as seconary_person_id, first_name, middle_name, last_name, date_of_birth from person_table;
Is there a better way to deal with this that I'm missing?
What you are showing in that figure is called "circular reference" (I think Qlikview calls it "Synthetic Key") and it is something that you should really try to avoid since it may make your app, not crash, but show incorrect results (which is worse).
In my opinion you have two options:
Op1 - Duplicate your PERSON_TABLE so that PRIMARY_PERSON_ID will be linked to PERSON_TABLE_1 and SECONDARY_PERSON_ID will be linked to PERSON_TABLE_2.
PERSON_TABLE_1:
SQL SELECT person_id as primary_person_id,
first_name as first_name_1,
middle_name as middle_name_1,
last_name as last_name_1,
date_of_birth as date_of_birth_1
FROM person_table
PERSON_TABLE_2:
SQL SELECT person_id as secondary_person_id,
first_name as first_name_2,
middle_name as middle_name_2,
last_name as last_name_2,
date_of_birth as date_of_birth_2
FROM person_table
The problem with this option is that you have to choose different alias for each field, which is usually not very convenient depending on the type of analysis you do in your app.
Op2: Create a unique MARRIAGE_TABLE already including the data of the two people. For that you can create a SQL query with two JOINS (I will only use first and middle names for simplicity, but you can add all the other fields)
SELECT T1.*, T2.first_name as first_name_1, T2.middle_name as middle_name_1,
T3.first_name as first_name_2, T3.middle_name as middle_name_2
FROM MARRIAGE_TABLE AS T1
LEFT JOIN PERSON_TABLE AS T2 ON Q1.primary_person_id = T2.person_id
LEFT JOIN PERSON_TABLE AS T3 ON Q1.secondary_person_id = T3.person_id
which will result in a unique table with the following columns:
MARRIAGE_ID PRIMARY_PERSON_ID SECONDARY_PERSON_ID MARRIAGE_START_DATE MARRIAGE_END_DATE FIRST_NAME_1 MIDDLE_NAME_1 FIRST_NAME_2 MIDDLE_NAME_2

MySQL insert into table with a set of values

I need to insert a table with some values (eg: 'NDA' in this case). This seems to work well if I have just one value to be inserted. I have around a dozen of similar values, is there a was i can tweak this query to insert say { 'NDA', 'SDM', 'APM' } values. Was curious to know if it can be done without a stored procedure or copy pasting the same statements over and changing the values.
INSERT IGNORE INTO customer_feature (customer_id, feature)
SELECT c.id, 'NDA' FROM
customer as c
where c.edition = 'FREE_TRIAL';
Reference: mysql -> insert into tbl (select from another table) and some default values
Is this what you want?
INSERT IGNORE INTO customer_feature(customer_id, feature)
select c.id, f.feature
from customer c cross join
(select 'NDA' as feature union all select 'SDM' union all select 'APM'
) f
where c.edition = 'FREE_TRIAL';

Dynamic query string

I want to add some dynamic content in from clause based on one particular column value.
is it possible?
For Example,
SELECT BILL.BILL_NO AS BILLNO,
IF(BILL.PATIENT_ID IS NULL,"CUS.CUSTOMERNAME AS NAME","PAT.PATIENTNAME AS NAME")
FROM
BILL_PATIENT_BILL AS BILL
LEFT JOIN IF(BILL.PATIENT_ID IS NULL," RT_TICKET_CUSTOMER AS CUS ON BILL.CUSTOMER_ID=CUS.ID"," RT_TICKET_PATIENT AS PAT ON BILL.PATIENT_ID=PAT.ID")
But This query is not working.
Here
BILL_PATIENT_BILL table is a common table.
It can have either PATIENT_ID or CUSTOMER_ID. If a particular record has PATIENT_ID i want PATIENTNAME in RT_TICKET_PATIENT as NAME OtherWise it will hold CUSTOMER_ID. If it is i want CUSTOMERNAME as NAME.
Here I m sure That BILL_PATIENT_BILL must have either PATIENT_ID or CUSTOMER_ID.
Can anyone help me?
You can also use IF() to select the right values instead of constructing your query from strings:
SELECT
BILL.BILL_NO AS BILLNO,
IF( BILL.PATIENT_ID IS NULL, cus.CUSTOMERNAME, pat.PATIENTNAME ) AS NAME
FROM
BILL_PATIENT_BILL AS BILL
LEFT JOIN RT_TICKET_CUSTOMER cus ON BILL.CUSTOMER_ID = cus.ID
LEFT JOIN RT_TICKET_PATIENT pat ON BILL.PATIENT_ID = pat.ID
However, it would also be possible to PREPARE a statement from strings and EXECUTE it but this technique is prone to SQL injections, i can only disadvise to do so:
read here: Is it possible to execute a string in MySQL?

INSERT INTO between tables with INNER JOIN

An earlier data import in CiviCRM placed some member numbers into a custom field (member_number) instead of the more useful (external_id) field.
My (admittedly limited) SQL skills are way too rusty, but what I'm trying to do is:
IF external_id field is empty,
AND the contact_type is "Individual"
THEN copy the data from member_number to external_id for the matching internal id number.
I've tried a few variations of this, with different errors:
INSERT INTO test_table (external_id)
SELECT member_number
FROM member_info
INNER JOIN test_table
ON memberinfo.entity_id=test_table.id
WHERE test_table.external_id IS NULL AND test_table.contact_type = "Individual"
Do I even really need the INNER JOIN on this? And I know the WHERE statement usually refers to the table you're pulling from, not the one you're inserting to, but I can't remember the right way to do this.
update test_table
set external_id =
if(external_id = '' and contact_type = 'Individual', member_number,external_id)

Help with MySQL UPDATE with Subquery

Need some help with this one... I need to update a column in one of my tables which was getting populated with 0 instead of the correct value. There's thousands of entries and I want to attempt to do this through a SQL script rather than PHP.
As an example, the player table consists of the columns (playerID, teamID, cityID, and stateID). stadium table has (statiumID, teamID, cityID, and stateID). The cityID in Table2 was set to 0 with some incorrect code. I know I can resolve this with a subquery, but I'm relatively new to the concept. I've come up with the following, but I have the feeling it's not very optimized:
UPDATE
`database1`.`stadium`
SET
`stadium`.`cityID` =
(
SELECT
`player`.`cityID`
FROM
`database2`.`player`
WHERE
`player`.`teamID` = `stadium`.`teamID`
AND
`player`.`stateID` = `stadium`.`stateID`
)
WHERE
`stadium`.`cityID` = 0;
I'm fairly certain this statement isn't optimized and could be cleaned up. Any help would be greatly appreciated!!!!
I think you want something like this.
UPDATE
database1.stadium AS s
INNER JOIN (
SELECT DISTINCT teamID, stateID, cityID FROM database2.player
) AS p
USING (teamID, stateID)
SET
s.cityID = p.cityID
WHERE
s.cityID = 0