The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.
Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by ronald.torres.h, 2023-08-14 13:05:07

RPT101i SQL I (With Answers)

RPT101i SQL I (With Answers)

EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Binary Operators Functions can take any number of inputs and perform complex operations to produce a single output. In contrast, a binary operator performs a simple operation on exactly two inputs. Assuming a binary operator exists that meets your needs, using it will likely make your query easier to read, easier to maintain, and better performing than if you use a function. The binary operators listed in this section all have the same syntax: value1 operator value2 where value1 and value2 have similar data types. Definitions are below and examples are shown throughout this lesson. Arithmetic Operators All arithmetic operators can be used with numeric values. Some can also be used with date/times as noted. Operator Description + Addition. Can also be used to add whole or partial days ﴾represented by a numeric value﴿ to a date/time value ‐ Subtraction. Can also be used to subtract whole or partial days ﴾represented by a numeric value﴿ to a date/time value. Can even be used with two date/time values to return the length of a time interval in days; in SQL Server the result is a date/time that must be cast to numeric ﴾covered later in this lesson﴿, in Oracle the result is numeric. * Multiplication. / Division. % SQL Server only Modulus: the remainder when one number is divided by another. Functions 5 • 6 RPT101i SQL I 101


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The % operator is specific to SQL Server. In Oracle, this same action can be accomplished using the MOD function: SELECT MOD( 1979, 100 ) "YY" FROM DUAL returns the value 79. In Oracle, the SELECT statement must include a FROM clause even if you're not retrieving data from the database. In such cases ﴾for example, when you're learning SQL﴿ use the DUAL table: an automatically created table that includes one row and one column. Concatenation Operator Operator Description + SQL Server only Appends two string values together. If either value is null, the result is NULL . || Oracle only Appends two string values together. If one of the strings is NULL , the result is the value of the other string. 5 • 7 Functions 102 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Use Functions in SQL SQL allows you to query data as it exists in the database as well as manipulate the data for output. This ability is provided through the use of functions. A function is a snippet of code that takes some number of inputs, also called arguments, and returns some sort of output, also called a result. Some functions don't take any arguments, but will still return a value. For example, CURRENT_TIMESTAMP returns the current date and time from the system. This is incredibly useful in comparing dates and lengths of time, such as in queries where you want to find all patients within a certain age range, or all new charges from the last month. Exercise 1: Functions and Arguments In this exercise, you'll learn about how functions take arguments by doing a case study on some date/time functions. 1. MONTH is a function that takes in one argument, a date, and returns the month value from the date. Fill in the chart below. ﴾Dates are given in the order month, day, year.﴿ Date MONTH ﴾ Date ﴿ '01/04/2009 23:42' 1 'June 16 1964' 6 '9‐4‐85' 9 'May 31, 1990' 5 '10‐21‐2015' 10 MONTH is a SQL Server function. In Oracle, similar functionality can be accomplished with the EXTRACT(datepart FROM date) function. For example, EXTRACT( MONTH FROM TO_DATE( '01/04/2009 23:42', 'MM/DD/YYYY HH24:MI' ) ) would return 1. In the above example, the TO_DATE function is first used to convert a string into a date. 2. Some functions take multiple arguments. The DATEADD function takes three arguments: an interval Functions 5 • 8 RPT101i SQL I 103


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 ﴾also called a datepart﴿, a number, and a date. For brevity, a datepart can be replaced with an abbreviation. Here are some of the more common dateparts: datepart Abbreviations day dd, d month mm, m week wk, ww year yy, yyyy hour hh minute mi, n DATEADD will take the number of the intervals ﴾as defined by the datepart﴿ and add it to ﴾or subtract it from﴿ the date. Fill in the blanks in the queries below: SELECT DATEADD( d, 15, '04 JAN 2009 23:42' ) ‐‐ = 2009‐01‐19 SELECT DATEADD( m, 1, '16 JUN 1964' ) ‐‐ = 16 JUL 1964 SELECT DATEADD( yy, ‐5, '9‐4‐85' ) ‐‐ = 04 SEP 1980 SELECT DATEADD( d, ‐3, '31 MAY 1990' ) ‐‐ = 1990‐05‐28 SELECT DATEADD( yy, ‐30, '21 OCT 2015' ) ‐‐ = 1985‐10‐21 Functions require arguments of the correct data type in the correct order. For example, the DATEADD function requires one datepart, one number, and one date or datetime, in that order. Any invalid input will cause an error, and the query will not run. 5 • 9 Functions 104 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 DATEADD is a SQL Server function. In Oracle, similar functionality can be accomplished with the ADD_MONTHS function and a little math. For example, ADD_MONTHS( TO_DATE( '9‐4‐85', 'MM‐DD‐YY' ) , ‐5 * 12 ) would return 04‐SEP‐80. When performing addition of days or fractions of a day, the addition operator is sufficient. For example, TO_DATE( '01/04/2009 23:42', 'MM/DD/YYYY HH24:MI' ) + 15 would return 19‐JAN‐09. Use Functions in the SELECT Clause When you use a function in the SELECT clause, you are creating a new column for your results. Consider the PATIENT table which has one row per patient. In the query... SELECT PAT_ID, MONTH( BIRTH_DATE ) "Birth Month" FROM PATIENT ...the MONTH function will run once per row in the PATIENT table. For each patient, the query will return the patient's ID and the "Birth Month" of the patient. Recall that temporarily adding extra columns to the SELECT clause can help you troubleshoot and validate the SELECT statement. In particular, to check if a function is behaving as desired, add the arguments of the function to the columns list of the SELECT clause. Run your modified query and compare the values returned by the function with the columns you just added. Building on the previous example, adding the BIRTH_DATE column to the SELECT clause of the previous query... SELECT PAT_ID, BIRTH_DATE, MONTH( BIRTH_DATE ) "Birth Month" FROM PATIENT ...and then running the query and analyzing the results makes it apparent how the MONTH function behaves. Functions 5 • 10 RPT101i SQL I 105


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 In this example... SELECT CURRENT_TIMESTAMP "Current Date" ...you create a column called "Current Date" that returns a value not dependent on the data set. Instead, the value returned is the date and time on the server when the query is run. A small number of functions that take no arguments, such as CURRENT_TIMESTAMP , do not require parentheses. Use Functions in Other Clauses In addition to the SELECT clause, functions may be used in other clauses including the WHERE clause and ORDER BY clause. However, doing so may have a significant impact on the efficiency of your query. This will be explored and discussed in further detail in the Performance lesson. 5 • 11 Functions 106 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Discovering Functions In the following exercises, you'll see several new functions in real‐world applications. In Microsoft SQL Server Management Studio, placing your cursor in a function name and pressing the F1 key typically brings up online help text. This does not work in the cert environments, so you can find the same help text by searching for any function name at https://docs.microsoft.com/ . In the Microsoft SQL function help text, optional variables appear in square brackets. For Oracle, similar function documentation can be found at https://docs.oracle.com/database/121/SQLRF/functions.htm . Exercise 2: Convert Numeric to String In this exercise, you'll practice using the concatenation operator and learn how to use the CAST function. Background The CLARITY_DEP table has one row per department The DEPARTMENT_ID column holds the department's ID The DEPARTMENT_NAME column holds the department's name Columns that include a combination of a name and a unique identifier can be useful for the final output of a query Task For each department return the department name followed by a space and then the department's ID in brackets [], all in one column. Step‐by‐Step 1. Try to run the following query: SELECT DEPARTMENT_NAME + ' [' + DEPARTMENT_ID + ']' FROM CLARITY_DEP 2. What error is returned? Error converting data type varchar to numeric Functions 5 • 12 RPT101i SQL I 107


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 In SQL, you can't combine different types of data without first converting the data types to be compatible. In Oracle, the query SELECT DEPARTMENT_NAME || ' [' || DEPARTMENT_ID || ']' FROM CLARITY_DEP runs successfully. Converting data types is still occurring: it's just being done implicitly by SQL. Explicitly converting data types may still be necessary in some cases. 3. Modify your query to: SELECT DEPARTMENT_NAME + ' [' + CAST( DEPARTMENT_ID AS varchar ) + ']' "Department" FROM CLARITY_DEP In SQL Server, the data type in the CAST function has a default length of 30. In Oracle, the C AST function requires a length, for example: CAST( DEPARTMENT_ID AS varchar2(30) ) 4. What does the CAST function do? Changes data from one data type to another Exercise 3: Convert Date/Time to String In this exercise, you'll learn how to use the SQL Server CONVERT function and learn about the corresponding Oracle TO_CHAR functions. Background The PATIENT table has one row per patient The PAT_NAME column holds the patient's name The BIRTH_DATE column holds the patient's date of birth Task List each patient's name and date of birth. Format the date of birth as mm/dd/yyyy, with no time listed. Step‐by‐Step 1. Run the following query: 5 • 13 Functions 108 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 SELECT PAT_NAME, BIRTH_DATE FROM PATIENT The BIRTH_DATE column is a datetime. Datetime data is always returned the same way, with a time down to the millisecond. To change the formatting, this date needs to be changed into a string ﴾varchar﴿. Now, the BIRTH_DATE column looks different, but it still returns a time of 12:00AM. You need to find a format that will hide the time part. 2. Modify your query to: SELECT PAT_NAME, CONVERT( varchar, BIRTH_DATE ) "Birth Date" FROM PATIENT The CONVERT function works similarly to the CAST function but is specific to SQL Server and has an additional optional parameter that will be explored below. Similar functionality is possible with the TO_CHAR functions in Oracle. Now, the BIRTH_DATE column looks different, but it still returns a time of 12:00AM. You need to find a format that will hide the time part. 3. Look up the online help text for the CONVERT function and find the Date and Time Styles ﴾see the beginning of the Discovering Functions section for accessing Microsoft's online help text﴿. Which of the Date and Time Styles would return a date in the format mm/dd/yyyy? 101 4. Change your query to return the BIRTH_DATE in this format: SELECT PAT_NAME, CONVERT( varchar, BIRTH_DATE, 101 ) "Birth Date" FROM PATIENT Exercise 4: Date/Time Functions In this exercise, you'll learn how to use some date/time functions. Background The PAT_ENC table has one row per encounter The PAT_ENC_CSN_ID column holds the CSN The CONTACT_DATE column holds the contact date Functions 5 • 14 RPT101i SQL I 109


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The DEPARTMENT_ID column holds the department's ID Task A Generate a list of encounters in the next 30 days. Step‐by‐Step 1. Create a new query that returns the CSN, Contact Date, and Department ID for all rows of the PAT_ENC table. Your query will look similar to the following: SELECT PAT_ENC_CSN_ID, CONTACT_DATE, DEPARTMENT_ID FROM PAT_ENC 2. Try adding the following WHERE clause: WHERE CONTACT_DATE = CURRENT_TIMESTAMP This query returns no results. An equals sign is not appropriate here; this query looks for contacts at the exact millisecond the query is run. When filtering based on dates, you will often need to use a range. CURRENT_TIMESTAMP might work as a lower bound for the range, but the upper bound needs to be the date 30 days from now. 3. Remove the WHERE clause, then modify your query to the following: SELECT PAT_ENC_CSN_ID, CONTACT_DATE, DEPARTMENT_ID, DATEADD( d, 30, CURRENT_TIMESTAMP ) FROM PAT_ENC 4. What does DATEADD( d, 30, CURRENT_TIMESTAMP ) return? The date and time exactly 30 days from now 5. Remove DATEADD( d, 30, CURRENT_TIMESTAMP ) from your SELECT list. 6. For your query, you need contacts within the next thirty days. Add the following WHERE clause to the end of your query: WHERE CONTACT_DATE BETWEEN CURRENT_TIMESTAMP AND DATEADD( d, 30, CURRENT_TIMESTAMP ) Task B 5 • 15 Functions 110 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Add a column to your results to return how many days away these contacts are. Step‐by‐Step 1. Look up the online help text for the DATEDIFF function ﴾see the beginning of the Discovering Functions section for accessing Microsoft's online help text﴿. 2. What arguments does the DATEDIFF function take? Datepart, startdate, enddate 3. Add a column to your query to return how many days away each upcoming encounter is. SELECT PAT_ENC_CSN_ID, CONTACT_DATE, DEPARTMENT_ID, DATEDIFF( d, CURRENT_TIMESTAMP, CONTACT_DATE ) "Days to Enc" FROM PAT_ENC WHERE CONTACT_DATE BETWEEN CURRENT_TIMESTAMP AND DATEADD( d, 30, CURRENT_TIMESTAMP ) Here is how a similar query would look in Oracle: SELECT PAT_ENC_CSN_ID, CONTACT_DATE, DEPARTMENT_ID, CONTACT_DATE ‐ CURRENT_TIMESTAMP "Days to Enc" FROM PAT_ENC_APPT WHERE CONTACT_DATE BETWEEN CURRENT_TIMESTAMP AND ( CURRENT_TIMESTAMP + 30 ) Task C Change your query to find all of the encounters that occurred last year up to today's date last year. Step‐by‐Step 1. Clear out your existing WHERE clause. 2. Look up the online help text for the DATEFROMPARTS function and find the Date and Time Styles ﴾see the beginning of the Discovering Functions section for accessing Microsoft's online help text﴿. 3. What is the datatype of all of the arguments for the DATEFROMPARTS function? Integer 4. What is the return type for the DATEFROMPARTS function? Date Functions 5 • 16 RPT101i SQL I 111


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 5. Change your WHERE clause to find contacts that occurred last year up to today's date last year. You can also use the functions YEAR , MONTH , DAY , and CURRENT_TIMESTAMP . Here is one possible solution: SELECT PAT_ENC_CSN_ID, CONTACT_DATE, DEPARTMENT_ID, DATEDIFF( d, CURRENT_TIMESTAMP, CONTACT_DATE ) "Days to Enc" FROM PAT_ENC WHERE CONTACT_DATE <= DATEFROMPARTS( YEAR( CURRENT_TIMESTAMP ) ‐ 1, MONTH( CURRENT_TI MESTAMP ), DAY( CURRENT_TIMESTAMP ) ) AND YEAR( CONTACT_DATE ) = YEAR( CURRENT_TIMESTAMP ) ‐ 1 Exercise 5: Convert Numeric to String with Formatting In this exercise, you'll practice using the division and concatenation operators, learn how to use the SQL Server STR function, and learn about the corresponding Oracle TO_CHAR functions. Background The VisitFact table has one row per face‐to‐face encounter The AppointmentLengthInMinutes column holds the scheduled length of the encounter in minutes Task For each face‐to‐face patient encounter, list the scheduled length of the encounter in hours, rounded to two decimal places and with the text ' hr' at the end. For example, '1.25 hr'. Step‐by‐Step 1. Run the following query in the SQL Management Studio named Study SQL Studio from access.epic.com ﴾euaccess.epic.com﴿: SELECT AppointmentLengthInMinutes "Minutes", AppointmentLengthInMinutes / 60 "Hours" FROM VisitFact For rows in which AppointmentLengthInMinutes is populated, notice that the "Hours" column is always an For rows in which AppointmentLengthInMinutes is populated, notice that the "Hours" column is always an integer. This is because AppointmentLengthInMinutes and 60 are both integers, so the division operator is actually performing integer division and therefore returning an integer. 2. Add the following column to the end of your SELECT clause and run your query: AppointmentLengthInMinutes / 60.0 "Hours with Decimal" 5 • 17 Functions 112 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 60.0 is written as a decimal, so now the division operator is performing numeric division as expected and the result is a decimal. We're getting closer! Now we need a function that will control the number of decimal places and turn our result into a string so we can append additional text. 3. Look up the online help text for the STR function and find the Date and Time Styles ﴾see the beginning of the Discovering Functions section for accessing Microsoft's online help text﴿. The STR function is specific to SQL Server. Similar functionality is possible with the TO_CHAR functions in Oracle. 4. You want to turn your number of hours into a string, 5 characters long, with 2 decimals. Use the ST R function on your number of hours to create this string. Your SELECT list should now include the following: STR( AppointmentLengthInMinutes / 60.0, 5, 2 ) 5. Since the number of hours is now a string, you may also concatenate the text ' hr' at the end of it. Your query should now look like the following: SELECT AppointmentLengthInMinutes "Minutes", AppointmentLengthInMinutes / 60 "Hours", AppointmentLengthInMinutes / 60.0 "Hours with Decimal", STR( AppointmentLengthInMinutes / 60.0, 5 , 2 ) + ' hr' "Appt Length" FROM VisitFact Exercise 6: Concatenate Strings In this exercise, you'll practice using the concatenation operator and learn how to use the CONCAT function. Background The CLARITY_SER table has one row per provider The PROV_NAME column holds the provider's name The CLINICIAN_TITLE column holds the provider's title Task Return each provider's name and title in a single column. Step‐by‐Step 1. Type the following new query in the SQL Management Studio named Study SQL Studio from access.epic.com ﴾euaccess.epic.com﴿: Functions 5 • 18 RPT101i SQL I 113


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 SELECT PROV_NAME, CLINICIAN_TITLE FROM CLARITY_SER 2. You want to put PROV_NAME and CLINICIAN_TITLE into the same column. Try modifying your SELE CT list to the following: SELECT PROV_NAME + ', ' + CLINICIAN_TITLE This doesn't work, because the concatenation operator ﴾ + ﴿ can't handle one of its operands being NULL . If just one of the values being concatenated is NULL , the concatenation returns NULL . This problem is specific to SQL Server. In Oracle, the concatenation operator ﴾ || ﴿ can concatenate columns even when one is NULL. 3. Look up the online help text for the CONCAT function and find the Date and Time Styles ﴾see the beginning of the Discovering Functions section for accessing Microsoft's online help text﴿. 4. Instead of using the + operator to concatenate PROV_NAME and CLINICIAN_TITLE, use the CONCAT function. Modify your query to the following: SELECT CONCAT( PROV_NAME, ', ', CLINICIAN_TITLE ) "Provider" FROM CLARITY_SER Exercise 7: Coalesce Values In this exercise, you'll learn about the COALESCE function and practice using the CAST function. Background The PATIENT table has one row per patient The CUR_PRIM_LOC_ID column holds the patient's primary location's ID Location IDs are numeric The CITY column holds the city of the patient's address Task For each patient, return a value that indicates which location they most likely visit. In particular, return the primary location ID. If that's not available return the patient's address' city. If that's not available, return '*Unknown Location' Step‐by‐Step This could be accomplished using a CASE statement, but there is a SQL function that will make this easier. 5 • 19 Functions 114 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 1. Type the following new query into the SQL Management Studio named Study SQL Studio from access.epic.com ﴾euaccess.epic.com﴿ and run it: SELECT COALESCE( CITY, '*Unknown Location' ) FROM PATIENT 2. Change the function arguments to the following: COALESCE( CUR_PRIM_LOC_ID, CITY, '*Unknown Location' ) You will likely see an error. If so, what error is returned? Error converting data type varchar to numeric Location IDs are numeric, while cities are strings. COALESCE can take as many arguments as needed, but they all must be the same data type. 3. Fix the problem using another function from an earlier exercise. Feel free to modify your query further if you'd like. Your final query may look similar to the one below: SELECT COALESCE( CAST( CUR_PRIM_LOC_ID AS varchar ), CITY, '*Unknown Location' ) "Locat ion" FROM PATIENT Summary of Functions Arithmetic Function Description MOD(number_value1, n umber_value2) Oracle only Returns the remainder of number_value1 divided by number_value2. Data Type Conversion Functions 5 • 20 RPT101i SQL I 115


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Function Description CAST(expression AS d ata_type) Returns an expression in a new data_type. CONVERT(data_type, e xpression[, style]) SQL Server only Returns an expression in a new data_type. Optional style when converting dates to strings. TO_DATE(string[, for mat [, nslparam]]) Oracle only Converts a string to a date. The format overrides the default date format and nslparam can provide additional specificity. STR(float_expression [, length [, decimal s]]) SQL Server only Returns the number in float_expression as a string, with a defined total length and number of decimals. TO_CHAR(datetime [, format [, nlsparam]] ) Oracle only Converts a datetime to a string. The format overrides the default format and nslparam can provide additional specificity. TO_CHAR(number [, fo rmat [, nlsparam]]) Oracle only Converts a number to a string. The format overrides the default format and nslparam can provide additional specificity. Dates and Times Function Description CURRENT_TIMESTAMP Returns the current date and time. Does not need parentheses. GETDATE() SQL Server only Returns the current date and time. DATEADD(datepart, nu mber, date) SQL Server only Returns a datetime that is number more dateparts than the date. For example, DATEADD( d, 7, '1/1/2015' ) returns 1/8/2015. 5 • 21 Functions 116 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 ADD_MONTHS(date, int eger) Oracle only Returns a date that is integer months later than date. DATEFROMPARTS(year, month, day) SQL Server only Creates a date value given three numbers for year, month, and day. DAY(date) SQL Server only Returns the day of month in a given date. MONTH(date) SQL Server only Returns the number of the month in a given date. 1 = January, etc. YEAR(date) SQL Server only Returns the year number in a given date. EXTRACT(datepart FRO M date) Oracle only Returns a number that is the datepart of the date. YEAR , MONTH , and DAY are common dateparts. DATEDIFF(datepart, s tartdate, enddate) SQL Server only Returns the number of datepart boundaries crossed between the startdate and enddate. For example, DATEDIFF( yy, '12/31/2013', '3/15/2014' ) returns 1. Strings Functions 5 • 22 RPT101i SQL I 117


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Function Description CONCAT(string1, stri ng2 [, string3...]) Returns a string, made up of string1, string2, and optionally more strings. Treats NULL as an empty string. In SQL Server, this function can take an unlimited number of arguments. In Oracle, this function takes exactly two arguments. LEN(string) SQL Server only Returns the number of characters in any string. LENGTH(string) Oracle only Returns the number of characters in any string. CHARINDEX(substring, string[, position]) SQL Server only Returns the number of the character in string where the first occurrence of substring begins. Optionally indicate at which position to start. For example, CHARINDEX( 'c', 'acre' ) returns 2. INSTR(string, substr ing [, position [, o ccurrence]]) Oracle only Returns the number of the character in string where the first ﴾by default﴿ occurrence of substring begins. Optionally indicate at which position to start. For example, INSTR( 'acre', 'c' ) returns 2. SUBSTRING(string, st art, length) SQL Server only Returns part of a string, starting at the start position, and continuing for a given length. SUBSTR(string, start [, length]) Oracle only Returns part of a string, starting at the start position, and continuing for a given length. Nulls 5 • 23 Functions 118 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Function Description COALESCE(input1, inp ut2 [, input3...]) Returns the first non‐null input. ISNULL(check_express ion, replacement_val ue) SQL Server only If check_expression is NULL , returns replacement_value. Otherwise, returns check_expression. Similar to COALESCE , however it can only handle two expressions. Is processed more quickly than COALESCE . NVL(check_expression , replacement_value) Oracle only If check_expression is NULL , returns replacement_value. Otherwise, returns check_expression. Similar to COALESCE , however it can only handle two expressions. Is processed more quickly than COALESCE . Functions 5 • 24 RPT101i SQL I 119


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Additional Exercises Exercise 8: Use Functions with Dates In this exercise, you'll practice predicting the output of functions introduced earlier in this lesson. What would be the output of the following queries? Fill in the grids below. SELECT HOSP_ADMSN_TIME HAT, YEAR( HOSP_ADMSN_TIME ) Y, MONTH( HOSP_ADMSN_TIME ) M, DAY( HOSP_ADMSN_TIME ) D FROM PAT_ENC_HSP HAT Y M D 2013‐03‐14 2013 3 14 2013‐06‐23 2013 6 23 SELECT HOSP_ADMSN_TIME HAT, HOSP_DISCH_TIME HDT, DATEADD( d, 30, HOSP_DISCH_TIME ) DA, DATEDIFF( d, HOSP_ADMSN_TIME, HOSP_DISCH_TIME ) DD FROM PAT_ENC_HSP HAT HDT DA DD 2013‐03‐14 2013‐03‐31 2013‐04‐30 17 2013‐06‐23 NULL NULL NULL SELECT HOSP_ADMSN_TIME HAT, HOSP_DISCH_TIME HDT, COALESCE( HOSP_DISCH_TIME, HOSP_ADMSN_TIME, CURRENT_TIMESTAMP ) C FROM PAT_ENC_HSP 5 • 25 Functions 120 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 HAT HDT C 2013‐03‐14 2013‐03‐31 2013‐03‐31 2013‐06‐23 NULL 2013‐06‐23 NULL NULL YYYY‐MM‐DD ‐‐Date the query is run Exercise 9: Format Dates and Calculate Time Intervals In this exercise, you'll practice formatting dates and calculating time intervals. Background The PAT_ENC_HSP table has one row per hospital encounter The PAT_ID column holds the patient's ID The ADMISSION_PROV_ID column holds the admitting provider's ID The DISCHARGE_PROV_ID column holds the discharge provider's ID The DEPARTMENT_ID column holds the department ID The HOSP_ADMSN_TIME column holds the admission time The HOSP_DISCH_TIME column holds the discharge time Task Write a query that lists hospital encounters with the admission date in 2016. Return the patient's ID, the admitting provider's ID, the discharge provider's ID, the department ID, the admission time ﴾in the format MM/DD/YYYY﴿, the discharge time ﴾in the format MM/DD/YYYY﴿, and the "Number of Dates" the patient was in the hospital. Hint: the "Number of Dates" is not stored and must be calculated based on the admission date and discharge date. Exercise 10: Many Functions In this exercise, you'll practice using several types of functions. Task Modify the query from Exercise 9: Format Dates and Calculate Time Intervals to: Only include discharged patients ﴾HOSP_DISCH_TIME has a value﴿ Return default values ﴾of your choice﴿ instead of NULL for admission provider, discharge provider, Functions 5 • 26 RPT101i SQL I 121


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 and department Increase the accuracy of DATEDIFF by measuring in hours ﴾hh﴿ and dividing by 24.0 Since DATEDIFF counts boundaries crossed, measuring in days can sometimes yield misleading results. The DATEDIFF in days between '8‐1‐2015 11:59 PM' and '8‐2‐2015 12:01 AM' would be 1, because one day‐boundary was crossed. When using DATEDIFF , it may be best to use a smaller datepart than you think is necessary. 5 • 27 Functions 122 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Reviewing the Chapter Review Questions 1. True or False: All functions require the use of parentheses, regardless of whether they take any arguments. 2. True or False: Functions can be used in the SELECT clause. 3. True or False: Functions can be used in the WHERE clause. Review Key Functions 5 • 28 RPT101i SQL I 123


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Review Key 1. True or False: All functions require the use of parentheses, regardless of whether they take any arguments. False. One example: CURRENT_TIMESTAMP. 2. True or False: Functions can be used in the SELECT clause. True 3. True or False: Functions can be used in the WHERE clause. True Study Checklist 5 • 29 Functions 124 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Study Checklist Make sure you can define the following key terms: ☐ Arithmetic operator ☐ + operator ☐ ‐ operator ☐ * operator ☐ / operator ☐ Concatenation operator ☐ Function ☐ Argument ☐ CAST function ☐ COALESCE function ☐ CONCAT function ☐ CURRENT_TIMESTAMP function Make sure you can perform the following tasks: ☐ Find and use documentation for SQL functions ☐ Use a function to return a default value in place of a NULL value ☐ Perform arithmetic with numeric values ☐ Concatenate two string values ☐ Convert a value from one data type to another ☐ Convert a numeric value to a string value ☐ Convert a date/time value to a string value ☐ Return a portion of a date/time value as a numeric value ☐ Combine numeric values to return a date/time value ☐ Convert a string value to a numeric value ☐ Convert a string value to a date/time value Functions 5 • 30 RPT101i SQL I 125


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 ☐ Return the current date/time ☐ Add a time interval to a date/time value ☐ Determine the time interval between two date/time values ☐ Return the length of a string ☐ Return the location of a substring inside another string ☐ Return a specified portion of a string Make sure you fully understand and can explain the following concepts: ☐ How using functions is beneficial 5 • 31 Functions 126 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Join Tables Introduction Joining Tables Workflow Theory of Joining ﴾Entity Relationships﴿ Cardinality of a Relationship Join Types Inner Join Left Outer Join Cross Join Other Join Types Exercise 1: Using an Inner Join Exercise 2: Using a Left Outer Join Exercise 3: Adding Join Criteria Exercise 4: Adding More Tables Practice of Joining ﴾SQL Syntax﴿ Exercise 5: Female Patients and Their PCPs Exercise 6: PCPs and Their Female Patients Table Aliases When Table Aliases are Nice When Table Aliases are Required General Rules to Follow For N Entities There Will be N‐1 Relationships Entities are Tables Relationships are Foreign Keys Exercise 7: Multi‐Column Foreign Key Join in the ...‐to‐1 Direction 6 • 4 6 • 5 6 • 6 6 • 6 6 • 9 6 • 10 6 • 11 6 • 13 6 • 14 6 • 14 6 • 16 6 • 17 6 • 17 6 • 19 6 • 19 6 • 21 6 • 23 6 • 23 6 • 24 6 • 27 6 • 27 6 • 27 6 • 28 6 • 29 6 • 30 Join Tables 6 • 1 RPT101i SQL I 127


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Most Granular Table First INNER JOINs Then LEFT OUTER JOINs Exercise 8: Using General Rules Reviewing the Chapter 6 • 32 6 • 33 6 • 34 6 • 36 6 • 2 Join Tables 128 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Join Tables 6 • 3 RPT101i SQL I 129


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Introduction In prior lessons, our queries have been relatively simple in that they only returned information from one type of entity ﴾or from the SQL perspective, one table﴿. More typical queries need to include information about multiple entities: entities that are all related to each other in some way. Such a query must reference every entity and every relationship we want to take advantage of to generate the query result. This process is called joining tables. In this lesson, we begin with an overview of the workflow and syntax for joining tables. Then we'll discuss the theory of joining tables in the context of identifying the entities and relationships we want to include in our joins. Next we'll apply that theory to the practice of writing our queries. The lesson will end with some shortcuts and caveats to be aware of in the context of joining tables. By the End of This Lesson, You Will Be Able To... Describe when it is necessary to include multiple tables in a query Choose the proper method of joining tables Join tables in a query Use multiple tables in a query 6 • 4 Join Tables 130 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Joining Tables Workflow Writing a query that requires joining tables involves these steps: 1. Identify the entities and relationships 2. Define the cardinality of the relationships 3. Identify the logical expressions for those relationships 4. Determine whether to include entities for which the logical expressions are never satisfied 5. Write the FROM clause 6. Complete the SELECT statement Notice that several steps need to be done upfront before writing the actual query. These preparation steps become easier the more familiar you become with the business terms and data model related to the subject matter of the queries. Therefore, we'll walk through some case studies so you can get familiar with the preparation process, then we'll focus on translating that into SQL. Joining tables uses the following syntax: SELECT table_alias.COLUMN_ONE, /*...*/ FROM TABLE_ONE table_alias join_type JOIN TABLE_TWO table_alias ON join_condition join_type JOIN TABLE_THREE table_alias ON join_condition /*...*/ where each table alias in the FROM clause is unique each table alias in the other clauses is a table alias defined in the FROM clause each join type is one of several options each join condition is a unique logical expression These terms will be defined throughout this lesson. Join Tables 6 • 5 RPT101i SQL I 131


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Theory of Joining ﴾Entity Relationships﴿ When you need multiple entities within one query, you should first identify those entities. Multiple relationships between the entities are possible, so it's important to identify which relationships will be used by the query. "Patient encounter" and "provider" are two entities. Relationships between these entities include: a patient encounter's visit provider a patient encounter's primary care provider at the time of the visit a patient encounter's admitting provider a patient encounter's attending provider﴾s﴿ a patient encounter's discharge provider a patient encounter's follow‐up provider a patient encounter's billing attending provider For a query that needs to include information about patient encounters and providers, you need to identify which relationship﴾s﴿ will be referenced in the query. Once the entities and relationships are identified, each relationship needs to be defined in a way that will guide you to using the relationship in the query. This is formally known as determining the cardinality of the relationship. Cardinality of a Relationship The cardinality of a relationship should not be confused with a similarly named relational database concept: the cardinality of a column. The cardinality of a column is represented by a single number and is outside the scope of this lesson. A patient encounter has at most one admitting provider but could have multiple attending providers. A query that lists the admitting provider for each encounter will look different and be built differently from a query that lists the attending providers for each encounter. The admitting provider and attending provider relationships differ in cardinality. The cardinality of a relationship describes the numeric relationship between two entities. One way it can be summarized is with a phrase of the form "M to N" where M and N are each one of the following: Zero or One 6 • 6 Join Tables 132 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Zero or More One One or More To avoid ambiguity with other relationship cardinality phrasings, the phrase "M to One" ﴾when N is "One"﴿ may be written as "M to One exactly". An entity relationship diagram can be helpful to quickly communicate a set of entities and relationships. There are many valid, popular methods for diagraming entity relationships, so any specific method is outside the scope of the SQL assessments. Pick a method that works for you, and try diagramming out some of the relationships referenced in the upcoming exercises and examples. Epic's entity relationship diagrams use a variation of crow's foot notation: each entity is a box, each relationship is a line, and the style of the endpoints of the line indicate the relationship cardinality. Notation N Zero or One Zero or More One exactly One or More A "One to Zero or More" patient‐encounter relationship would look like this: A "Zero or More to Zero or More" encounter‐provider relationship would look like this: A patient can have zero or more hospital encounters. A hospital encounter is for exactly one patient. Therefore, this patient‐encounter relationship is said to have a cardinality of "One to Zero or More." The inverse encounter‐patient relationship has a cardinality of "Zero or More to One exactly." Join Tables 6 • 7 RPT101i SQL I 133


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 A hospital encounter can have zero or more attending providers. A provider can be an attending provider for zero or more hospital encounters. Therefore, this encounter‐provider relationship has a cardinality of "Zero or More to Zero or More." Sometimes relationships that include the possibility of zero are phrased without the "zero." A patient can have many hospital encounters. A hospital encounter is for one patient. Therefore, this patient‐encounter relationship is said to have a cardinality of "1‐to‐many." The inverse encounter‐patient relationship has a cardinality of "many‐to‐1." A hospital encounter can have many attending providers. A provider can be an attending provider for many hospital encounters. Therefore, this encounter‐provider relationship has a cardinality of "many‐to‐many." At this point in the query writing process, you may want to revisit the entities and relationships you identified earlier, especially if you have a many‐to‐many relationship. Many‐to‐many relationships can cause issues as we'll explore, so we'll avoid them if we can. 6 • 8 Join Tables 134 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The encounter‐provider relationship ﴾as identified in a previous example﴿ is a many‐to‐many relationship. If possible, we'd like to break this down into simpler relationships. Instead of just two entities, we can imagine three entities: encounter provider attending provider assignment This last entity is a pairing of an encounter and a provider with a valid relationship. For example, if encounter 6216 has three attending providers ﴾Dr. Farm, Dr. Story, and Dr. Wizard﴿ then there are three "attending provider assignments": 6216‐Farm, 6216‐Story, and 6216‐Wizard. In essence, we've turned our many‐to‐many relationship into an entity. Does this help us? There are now two additional relationships to consider: The encounter‐"attending provider assignment" relationship has a cardinality of "One to Zero or More." The provider‐"attending provider assignment"‐relationship has a cardinality of "One to Zero or More." These are both 1‐to‐many relationships, so yes, this does help us! With the addition of a third entity, these two 1‐to‐many relationships can replace the many‐ to‐many relationship we had before. There is some flexibility with identifying entities vs. relationships. Ultimately what you identify may be influenced by how these are represented in the database and what your desired query result is. After you're satisfied with your relationship definitions, it's time to consider the desired query output and choose the appropriate join types. Join Types Each type of entity represented in a relational database is a table. To query one type of entity, we only need to query one table and the query result is a single table. If we need two types of entities, we need to query two tables, but the query result will still be a single table. Each row in this new table is defined by the relationship between the two entities: if a row in the first table has a valid relationship with a row in the second table, then we can return information from both source rows in a single row of the results. Join Tables 6 • 9 RPT101i SQL I 135


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The encounter‐patient relationship ﴾as identified in a previous example﴿ has a cardinality of "Zero or More to One exactly." Since each encounter has "exactly one" patient, each row of the query that has encounter information will also have corresponding patient information. But patients can have "zero or more" encounters: what will happen to patients who don't have any encounters? They won't have any encounter information, so will they be in the result of the query? The answer: you get to decide by choosing the appropriate join type. The join type of a join dictates whether or not rows in one table that have no valid matches in the other table will be in the query result. Inner Join The INNER JOIN ﴾or just JOIN ﴿ keyword is used to perform an inner join. An inner join only includes rows that represent a match between the two tables. This is an appropriate choice for relationship cardinalities that don't include "Zero or..." on either side. This is also an appropriate choice if your query result should only include valid matches. Finally, inner joins are preferred because they typically perform better than the other joins. The PAT_ENC_HSP table has one row per hospital encounter The DISCHARGE_PROV_ID column holds the discharge provider's ID This is a foreign key to the CLARITY_SER table This is a "Zero or More to Zero or One" relationship The CLARITY_SER table has one row per provider The PROV_ID column holds the provider's ID This is the primary key The PROV_NAME column holds the provider's name There is a "Zero" on both sides of the relationship cardinality, so be hesitant about using an inner join. However, if our desired result is to only return hospital encounters that have discharge providers, then an inner join will work. The query SELECT PAT_ENC_HSP.PAT_ENC_CSN_ID "CSN", CLARITY_SER.PROV_NAME "Provider Name" FROM PAT_ENC_HSP INNER JOIN CLARITY_SER ON PAT_ENC_HSP.DISCHARGE_PROV_ID = CLARITY_SER.PROV_ID will result in one row per hospital encounter that has a discharge provider. If there is no discharge provider, the hospital encounter will not have a row in the result. 6 • 10 Join Tables 136 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Left Outer Join The LEFT OUTER JOIN ﴾or just LEFT JOIN ﴿ keyword is used to perform a left outer join. As the name implies, there are left and right sides, and the sides matter. A left outer join keeps rows in the left table even if there is no match in the right table. In such rows, columns from the right table all return NULL . A left outer join discards rows in the right table that don't have a valid match in the left table. This is an appropriate choice for relationship cardinalities that have "Zero or..." on the right side and your query result should include rows in the left table even if there is no match in the right table. If you'd like to keep all rows in the right table rather than the left, it's customary to swap the order of the tables ﴾and therefore the relationship cardinality﴿ so you can use a left outer join. The PAT_ENC_HSP table has one row per hospital encounter The DISCHARGE_PROV_ID column holds the discharge provider's ID This is a foreign key to the CLARITY_SER table This is a "Zero or More to Zero or One" relationship The CLARITY_SER table has one row per provider The PROV_ID column holds the provider's ID This is the primary key The PROV_NAME column holds the provider's name There is a "Zero or..." on the right side of the relationship cardinality, so a left outer join should be considered. Specifically, if our desired result is to include hospital encounters even if they don't have a discharge provider, then a left outer join is appropriate. The query SELECT PAT_ENC_HSP.PAT_ENC_CSN_ID "CSN", CLARITY_SER.PROV_NAME "Provider Name" FROM PAT_ENC_HSP LEFT OUTER JOIN CLARITY_SER ON PAT_ENC_HSP.DISCHARGE_PROV_ID = CLARITY_SER.PROV_ID will result in one row per hospital encounter. If there is no discharge provider, the "Provider Name" column will be NULL. Join Tables 6 • 11 RPT101i SQL I 137


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 In the example above, PAT_ENC_HSP is considered the left table because it comes before the LEFT OUTER JOIN . While it is customary to list the columns in the join condition in the same order, it is not required. A query with the following FROM clause would return the same result: FROM PAT_ENC_HSP LEFT OUTER JOIN CLARITY_SER ON CLARITY_SER.PROV_ID = PAT_ENC_HSP.DISCHARGE_PROV_ID In order to respect a LEFT OUTER JOIN , any logical expressions that should only affect the right table need to be included in the JOIN condition, not the WHERE clause. There are a couple of ways to think about this. Conditions in the WHERE clause remove rows from the overall query result whereas a LEFT OUTER JO IN condition just ignores mismatches in the right table. The WHERE clause is processed after the FROM clause. 6 • 12 Join Tables 138 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The PAT_ENC table has one row per patient encounter The PAT_ENC_CSN_ID column is the primary key The PAT_ENC_DX table has one row per encounter diagnosis The PAT_ENC_CSN_ID column is one of two columns in the primary key This is a foreign key to the PAT_ENC table The DX_ID column holds the internal ID of the diagnosis The PRIMARY_DX_YN column indicates if the diagnosis is the primary diagnosis for the encounter For a given encounter, at most one diagnosis can be the primary diagnosis A value of 'Y' indicates a primary diagnosis The query SELECT PAT_ENC.PAT_ENC_CSN_ID "CSN", PAT_ENC_DX.DX_ID "Diagnosis ID" FROM PAT_ENC LEFT OUTER JOIN PAT_ENC_DX ON PAT_ENC.PAT_ENC_CSN_ID = PAT_ENC_DX.PAT_ENC_CSN_ID will result in at least one row per patient encounter: one row if there are zero encounter diagnoses one row for each diagnosis if there are diagnoses If we add on WHERE PAT_ENC_DX.PRIMARY_DX_YN = 'Y' then the result will have at most one row per patient encounter: zero rows if there are zero primary encounter diagnoses one row if there is a primary encounter diagnosis Recall that adding a WHERE clause always maintains or reduces the number of rows in the result. Rather than adding a WHERE clause, if we instead add on AND PAT_ENC_DX.PRIMARY_DX_YN = 'Y' to the FROM clause then the result will have exactly one row per patient encounter: If there isn't a primary diagnosis then "Diagnosis ID" will be NULL If there is a primary diagnosis then "Diagnosis ID" will be the primary diagnosis Cross Join Join Tables 6 • 13 RPT101i SQL I 139


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The cross join is rarely used on purpose but it is included here as a caution. Cross joins can be mistakenly performed a couple of ways: Skipping the JOIN keywords and instead separating tables in your FROM clause with commas; no O N keyword is used and there is no join condition. Using one of the other join types with a join condition that always evaluates to TRUE. In either case, there is no join condition. The cross join results in what is known as a Cartesian product: every possible combination of rows in the first table with rows in the second table. The CLARITY_LOC table has one row per location The CLARITY_DEP table has one row per department If the CLARITY_LOC table has 500 rows and the CLARITY_DEP table has 3,000 rows, then the cross join of these two tables will have 500x3,000 = 1,500,000 rows. Each row in the result will have information from a row in the CLARITY_LOC table and a row in the CLARITY_DEP table, but there is no meaningful relationship between the two in the result. Cartesian products should be avoided because: The result is usually massive and therefore performance intensive to produce. The result is usually meaningless. If your query results in a Cartesian product or has properties similar to a Cartesian product, here are some potential reasons and remedies: The relationship you selected isn't fully accounted for in the join condition. Modify your join condition. The relationship you selected is a many‐to‐many relationship. See if you can reduce this to simpler relationships. Other Join Types Inner and left outer joins are by far the most popular type of joins in published SQL queries. Fully investigate the desired result of your query if you think those two join types will not suffice. That said, there are other join types that are outside the scope of this lesson. Exercise 1: Using an Inner Join In this exercise, you'll practice using an inner join and then learn some details about using inner joins. Background The HSP_ACCT_DX_LIST table has one row per coded final diagnosis for a hospital account 6 • 14 Join Tables 140 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 The HSP_ACCOUNT_ID column holds the hospital account ID This is one of the primary key columns This is a foreign key to the HSP_ACCOUNT table This is a "Zero or More to Exactly One" relationship The FINAL_DX_POA_C column indicates whether the diagnosis was present on admission ﴾POA﴿. A value of 1 indicates 'Yes' The DX_ID column holds the diagnosis ID This is a foreign key to the CLARITY_EDG table This is a "Zero or More to Exactly One" relationship The HSP_ACCOUNT table has one row per hospital account The HSP_ACCOUNT_ID column holds the hospital account ID This is the primary key The HSP_ACCOUNT_NAME column holds the patient's name The CLARITY_EDG table has one row per diagnosis definition The DX_ID column holds the diagnosis ID This is the primary key The DX_NAME column holds the diagnosis name Task Use an inner join to return the patient name, hospital account ID ﴾HAR﴿, diagnosis ID, and POA indicator for each final diagnosis. Start your FROM clause with the HSP_ACCOUNT table. Save your query so you can build on it in Exercise 2: Using a Left Outer Join and Exercise 4: Adding More Tables. Follow‐Up Questions To answer these questions, temporarily modify your solution to try the proposed alternatives. 1. Does it matter if your FROM clause has HSP_ACCOUNT INNER JOIN HSP_ACCT_DX_LIST vs. HSP_ACCT_DX_L IST INNER JOIN HSP_ACCOUNT ? Why or why not? No. The INNER JOIN keyword treats both sides the same. 2. Does it matter if your join condition has HSP_ACCOUNT.HSP_ACCOUNT_ID = HSP_ACCT_DX_LIST.HSP_ACCOU NT_ID vs. HSP_ACCT_DX_LIST.HSP_ACCOUNT_ID = HSP_ACCOUNT.HSP_ACCOUNT_ID ? Why or why not? No. The equal operator treats both sides the same. Join Tables 6 • 15 RPT101i SQL I 141


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 3. Does it matter if your SELECT clause has HSP_ACCOUNT.HSP_ACCOUNT_ID vs. HSP_ACCT_DX_LIST.HSP_ACC OUNT_ID ? Why or why not? No. Both are populated and have the same value as enforced by the join condition of the INNER JOI N . Exercise 2: Using a Left Outer Join In this exercise, you'll practice using a left outer join and then learn some details about using left outer joins. Background See the Background for Exercise 1: Using an Inner Join. Task Use a left outer join to return the patient name, hospital account ID ﴾HAR﴿, diagnosis ID, and POA indicator for each final diagnosis. Start your FROM clause with the HSP_ACCOUNT table. You may find it useful to copy and modify your solution to Exercise 1: Using an Inner Join. Save your query so you can build on it in Exercise 3: Adding Join Criteria Follow‐Up Questions To answer these questions, temporarily modify your solution to try the proposed alternatives. 1. Does it matter if your FROM clause has HSP_ACCOUNT LEFT OUTER JOIN HSP_ACCT_DX_LIST vs. HSP_ACCT _DX_LIST LEFT OUTER JOIN HSP_ACCOUNT ? Why or why not? Yes. The LEFT OUTER JOIN keyword treats each side differently. 2. Does it matter if your join condition has HSP_ACCOUNT.HSP_ACCOUNT_ID = HSP_ACCT_DX_LIST.HSP_ACCOU NT_ID vs. HSP_ACCT_DX_LIST.HSP_ACCOUNT_ID = HSP_ACCOUNT.HSP_ACCOUNT_ID ? Why or why not? No. The equal operator treats both sides the same. 3. Does it matter if your SELECT clause has HSP_ACCOUNT.HSP_ACCOUNT_ID vs. HSP_ACCT_DX_LIST.HSP_ACC OUNT_ID ? Why or why not? Yes. HSP_ACCT_DX_LIST.HSP_ACCOUNT_ID may be NULL because of the LEFT OUTER JOIN . 4. Compare your answers above with those of Exercise 1: Using an Inner Join. For which join type ﴾inner or left outer﴿ should more care be taken to choose the proper order of tables in the FROM clause and to choose the columns from the proper tables in the SELECT clause? More care should be taken with left outer joins. 6 • 16 Join Tables 142 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Exercise 3: Adding Join Criteria In this exercise, you will practice adding a filter to the join criteria and compare that with adding the filter to the WHERE clause. As you explored in Exercise 1: Using an Inner Join and Exercise 2: Using a Left Outer Join, more care should be taken when a left outer join must be used. This includes when adding filters. Background See the Background for Exercise 1: Using an Inner Join. Task Use a left outer join to return the patient name, hospital account ID ﴾HAR﴿, diagnosis ID, and POA indicator for each final diagnosis that was present on admission. Start your FROM clause with the HSP_ACCOUNT table. Include the filter on the POA indicator in your join condition. You may find it useful to copy and modify your solution to Exercise 2: Using a Left Outer Join. Follow‐Up Questions To answer these questions, temporarily modify your solution to try the proposed alternatives. 1. Does it matter if the filter HSP_ACCT_DX_LIST.FINAL_DX_POA_C = 1 is in the join condition or a WHERE clause? Why or why not? Yes. Filtering in the join allows the possibility of no matches whereas filtering in the WHERE clause may discard some hospital accounts. 2. If you needed to return all hospital encounters even if they didn't have a final diagnosis that was present on admission, would you include the filter in the join condition or the WHERE clause? Filter in the join condition. Exercise 4: Adding More Tables In this exercise, you'll practice joining multiple times in one query. Then you'll learn about ordering the joins appropriately. Background See the Background for Exercise 1: Using an Inner Join. Task Use inner joins to return the patient name, hospital account ID ﴾HAR﴿, diagnosis name, and POA indicator for each final diagnosis. Start your FROM clause with the HSP_ACCOUNT table. You may find it useful to copy and modify your solution to Exercise 1: Using an Inner Join. Hint: what syntax did you add to your FROM clause when going from one table to two tables? Add something similar again to add a third table. Join Tables 6 • 17 RPT101i SQL I 143


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Follow‐Up Questions To answer these questions, temporarily modify your solution to try the proposed alternatives. 1. If you change the first INNER JOIN in your query to a LEFT OUTER JOIN does it affect the result? Why or why not? No. Both of the INNER JOIN s discard rows where the primary key (and therefore the rest of the columns) of HSP_ACCT_DX_LIST is NULL . The same rows are discarded even when one of the INNER JOIN s is removed. 2. If you change both INNER JOIN s in your query to LEFT OUTER JOIN s does it affect the result? Why or why not? Yes. The LEFT OUTER JOIN s will not discard rows from the HSP_ACCT_DX_LIST table. The takeaway here is the FROM clause evaluates one join at a time in the order listed. If you perform a left outer join, then the columns that came from the right table may be NULL for some rows. If you then perform an inner join, those rows may be discarded if NULL s are not properly handled. 6 • 18 Join Tables 144 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Practice of Joining ﴾SQL Syntax﴿ Now that you've seen the theory of joining, we're ready to run through some complete examples. Exercise 5: Female Patients and Their PCPs In this exercise, you'll practice all the steps of writing a query with two tables. Background The PATIENT table has one row per patient The PAT_ID column holds the patient's ID This column is the primary key The PAT_NAME column holds the patient's name The SEX_C column holds the patient's sex A value of '1' indicates 'Female' The CUR_PCP_PROV_ID column holds the patient's current general primary care provider's ID This column is a foreign key to CLARITY_SER.PROV_ID The CLARITY_SER table has one row per provider The PROV_ID column holds the provider's ID This column is the primary key The PROV_NAME column holds the provider's name A patient can have 0 or 1 current general primary care providers A provider can be the current general primary care provider of 0 or more patients Task Write a query to list each female patient's name. If the patient has a current general primary care provider, return that provider's name on the same row. Part 1: Identify the Entities and Relationships We need to return the name of the patient and the name of the provider, so there are two entities: the patient the provider The relationship between our entities is "patient's current general primary care provider." This is important because there are other valid relationships between our entities that are outside the scope of this task ﴾for example, a patient's hospital encounter's admitting provider﴿. Part 2: Define the Cardinality of the Relationships Join Tables 6 • 19 RPT101i SQL I 145


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 This patient‐provider relationship has the following properties: a patient can have zero or one provider a provider can have zero or more patients Therefore, the cardinality of the patient‐provider relationship is "Zero or More to Zero or One" or simply "many‐to‐1." Part 3: Identify the Logical Expressions for Those Relationships The foreign key PATIENT.CUR_PCP_PROV_ID represents this patient‐provider relationship and CLARITY_SER.PROV_ID is the corresponding primary key. Therefore, the logical expression for this relationship is: PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID This condition will get just female patients: PATIENT.SEX_C = '1' Recall that when multiple tables are involved, columns should be referenced by "TABLE_NAME.COLUMN_NAME". In this example's first logical expression, the CUR_PCP_PROV_ID and PROV_ID column names are unique across the PATIENT and CLARITY_SER tables, so this is technically unnecessary. However, including the TABLE_NAME increases readability. This also improves maintainability, specifically when you need to add more tables to your query later on. In this example's second logical expression, the SEX_C column name is not unique across the PATIENT and CLARITY_SER tables, so referencing both the table and the column name is necessary. Part 4: Determine What Should Happen to Entities for Which the Logical Expressions are Never Satisfied Because the cardinality of the relationship has a zero on both sides, we should consider how each entity should be manifested in the query result if there is no relationship. A patient can have zero or one provider. The Task indicates that we are to list each patient. Therefore, a patient should be returned even if they have no provider. A provider can have zero or more patients. The Task indicates that a provider should be listed only if a patient has that provider. Therefore, a provider should not be returned if they have no patients. Part 5: Write the FROM Clause Our research in the previous parts essentially dictates what our query should look like. A patient should be returned even if they have no provider, so the PATIENT table should be on the 6 • 20 Join Tables 146 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 left side of a LEFT OUTER JOIN . A provider should not be returned if they have no patient, so the CLARITY_SER table should be in an INNER JOIN or on the right side of a LEFT OUTER JOIN . These two conclusions dictate that we should perform a LEFT OUTER JOIN from the PATIENT table to the CLARITY_SER table. The FROM clause will look like this: FROM PATIENT LEFT OUTER JOIN CLARITY_SER ON PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID The remaining logical expression is a filter on our left table, so we'll leave that for our WHERE clause. Part 6: Complete the SELECT Statement Based on the Task we complete the rest of the SELECT statement: SELECT PATIENT.PAT_NAME, CLARITY_SER.PROV_NAME FROM PATIENT LEFT OUTER JOIN CLARITY_SER ON PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID ‐‐1=Female WHERE PATIENT.SEX_C = '1' Exercise 6: PCPs and Their Female Patients In this exercise, you'll practice all the steps of writing a query with two tables. Background See Exercise 5: Female Patients and Their PCPs. Task Write a query to list each provider's name. For each female patient that has that provider as their current general primary care provider, return that patient's name. Parts 1, 2, & 3 These parts are the same as in Exercise 5: Female Patients and Their PCPs. Part 4: Determine What Should Happen to Entities for Which the Logical Expressions are Never Satisfied A patient can have 0 or 1 provider. The Task indicates that a patient should be listed only if the patient has a provider. Therefore, a patient should not be returned if they have no provider. A provider can have 0 or more patients. The Task indicates that we are to list each provider. Join Tables 6 • 21 RPT101i SQL I 147


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Therefore, a provider should be returned even if they have no patients. Part 5: Write the FROM Clause Our research in the previous parts essentially dictates what our query should look like. A patient should not be returned if they have no provider, so the PATIENT table should be in an INN ER JOIN or on the right side of a LEFT OUTER JOIN . A provider should be returned even if they have no patient, so the CLARITY_SER table should be on the left side of a LEFT OUTER JOIN . These two conclusions dictate that we should perform a LEFT OUTER JOIN from the CLARITY_SER table to the PATIENT table. Recall that in order to respect a LEFT OUTER JOIN , any logical expressions on the right table need to be included in the JOIN condition, not the WHERE clause. The FROM clause will look like this: FROM CLARITY_SER LEFT OUTER JOIN PATIENT ON PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID AND PATIENT.SEX_C = '1' Part 6: Complete the SELECT Statement Based on the Task we complete the rest of the SELECT statement: SELECT CLARITY_SER.PROV_NAME, PATIENT.PAT_NAME FROM CLARITY_SER LEFT OUTER JOIN PATIENT ON PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID ‐‐1=Female AND PATIENT.SEX_C = '1' 6 • 22 Join Tables 148 RPT101i SQL I


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Table Aliases Like column aliasing, table aliasing allows you to assign new and temporary names to tables. When there is more than one table in your query, table aliases can improve the readability, thereby making your queries easier to maintain. Unlike column aliasing, table aliasing doesn't modify column headings. So, the benefits are mainly for the process of query writing, not the query results. However, there are some specific circumstances when aliasing tables is required, which we'll explore in this section. Table aliases are defined in the FROM clause. Because the FROM clause is evaluated first, table aliases can be used in all the clauses. There are many syntaxes for defining aliases, and several are version dependent. You can use the AS keyword in a table alias to make it explicit, but it is not required. If the table alias has a space in it, it must be enclosed in double quotes ﴾SQL Server also allows square brackets﴿. When Table Aliases are Nice Aliasing tables means that queries are typically shorter. Compare these two queries. SELECT PATIENT.PAT_NAME, PATIENT.SEX_C, CLARITY_SER.PROV_NAME, CLARITY_SER.SEX_C FROM PATIENT INNER JOIN CLARITY_SER ON PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID SELECT p.PAT_NAME, p.SEX_C, cs.PROV_NAME, cs.SEX_C FROM PATIENT p INNER JOIN CLARITY_SER cs ON p.CUR_PCP_PROV_ID = cs.PROV_ID The two queries produce the same result, but the latter query has fewer characters. Typically, published queries with more tables and columns will yield a more pronounced difference. Aliasing tables means being able to better align your query with business terms. Join Tables 6 • 23 RPT101i SQL I 149


EpicUUID: 5143F74D-DB01-4131-AAA3-52F4753E50D4 Compare these two queries. SELECT PATIENT.PAT_NAME, PATIENT.SEX_C, CLARITY_SER.PROV_NAME, CLARITY_SER.SEX_C FROM PATIENT INNER JOIN CLARITY_SER ON PATIENT.CUR_PCP_PROV_ID = CLARITY_SER.PROV_ID SELECT pat.PAT_NAME, pat.SEX_C, pcp.PROV_NAME, pcp.SEX_C FROM PATIENT pat INNER JOIN CLARITY_SER pcp ON pat.CUR_PCP_PROV_ID = pcp.PROV_ID The two queries produce the same result, but the latter query uses "pcp" to refer to the primary care provider as opposed to the actual table name CLARITY_SER. It's clearer that the second query is about primary care provider relationships as opposed to other patient‐ provider relationships. Typically, published queries with more tables and more obscure table names will yield a more pronounced benefit. When Table Aliases are Required Table aliasing is required when a table needs to be included in the FROM clause multiple times. Think about what that means: each table in the FROM clause represents a different entity; if a table is listed multiple times, then it must be used to represent multiple entities. Another way to think about it: if a single row of the query result needs to include information from two distinct rows of a table, then the table needs to be included in the FROM clause two times. All that said, if a table is included in the FROM clause more than once, then aliases are required to tell each copy apart. 6 • 24 Join Tables 150 RPT101i SQL I


Click to View FlipBook Version