Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
dogtag1
Starting Member
4 Posts |
Posted - 2005-08-05 : 12:42:24
|
Hi guys, I'm relatively new to SQL, and I've been working on a stored procedure to pull a bunch of records from 2 separate tables in a database and put them together. The way it works is that one table is a contact info table, the other is a billing table. They have a common field called contactID. what i need to do is pull all the records where the persons contract date (in the contact table) is between 2 dates, and also any payments they made between those dates (in the billing table). I had a stored procedure written that sort of worked, but it was missing a bunch of records. Also, after I pull this info, what i was thinking of doing was something like: create table #contactinfo ( contactid int, contractdate datetime, paymentdate datetime ) insert into #contactinfo select contactid, contractdate, null from contacts where contractdate >= @begindate and contractdate <= @Enddate insert into #contactinfo select contactid, null, paymentdate from billing where contractdate >= @begindate and contractdate <= @Enddate after i do this, i need to get rid of any duplicate contact IDs (which should have one or the other of a contract date or payment date) and make them one entry, with both a conractdate and paymentdate...this is where i'm stumped. after that, it should be easy enough. any thoughts? (and am i making this too difficult) thanks,Jeff |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-08-05 : 13:18:51
|
Hi dogtag1, Welcome to SQL Team!Does this do the job?CREATE TABLE contacts( contactid int, contractdate datetime)GOCREATE TABLE billing( contactid int, paymentdate datetime)GOINSERT INTO contactsSELECT 1, '01-Aug-2005' UNION ALLSELECT 2, '02-Aug-2005' UNION ALLSELECT 4, '04-Aug-2005' UNION ALLSELECT 31, '31-Dec-2005'GOINSERT INTO billingSELECT 1, '01-Aug-2005' UNION ALLSELECT 2, '02-Sep-2005' UNION ALLSELECT 3, '03-Sep-2005' UNION ALLSELECT 31, '31-Dec-2005'GOSELECT [contactid] = COALESCE(C.contactid, B.contactid), C.contractdate, B.paymentdateFROM ( SELECT contactid, contractdate FROM contacts WHERE contractdate > '01-Aug-2005' AND contractdate < '31-Dec-2005' ) C FULL OUTER JOIN ( SELECT contactid, paymentdate FROM billing WHERE paymentdate > '01-Aug-2005' AND paymentdate < '31-Dec-2005' ) B ON B.contactid = C.contactidORDER BY B.contactidGODROP TABLE contactsGODROP TABLE billingGO NOTE: The last line in your second query refers to contractdate, I've used paymentdate from the billing table as I wasn't sure yours was a typo. If there IS a contractdate in the billing table then it needs a little modification to the "criteria" stuff, but should otherwise be about the same.And IF there is a contractdate in the billing table is it really reasonable that you can have a billing record, with a contractdate, but not corresponding record in the contacts table? (If the answer is NO then you just need a LEFT OUTER JOIN and not all this complex FULL OUTER JOIN stuff )Kristen |
 |
|
|
dogtag1
Starting Member
4 Posts |
Posted - 2005-08-05 : 14:03:53
|
| ah crap, just wrote a long response but forgot to put my user name and password in. anyway the short version is that yes that was a typo, it was supposed to be paymentdate, and thata) contacts table is basically the center of the database meaning that there wont be any contactIDs in the billing table that arent in the contacts table because all records get added there before anything else can be done w/ them. i'm still new to sql, and although i understand how the embedded select statements you wrote in there work, it took me a second to visualize it all.ty,-jeff |
 |
|
|
dogtag1
Starting Member
4 Posts |
Posted - 2005-08-05 : 14:14:14
|
| you know what, i was just relooking at this and there's another part. i need to pull contracts from that day without payments on the same day (i.e. a downpayment when they signed the contract), a contract with a downpayment, and payments on old contracts (and the contract date so it can be listed) from that day. makes more sense than how i described it originally |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-08-05 : 14:18:16
|
OK, we can go with the simpler LEFT OER JOIN - provided that :What happens if the payment date is within range, but the corresponding contract date is NOT - does the contract date show up, or does it need to be NULL?The method below will include the out-of-range contract dateDROP TABLE contactsGODROP TABLE billingGOCREATE TABLE contacts( contactid int, contractdate datetime)GOCREATE TABLE billing( contactid int, paymentdate datetime)GOINSERT INTO contactsSELECT 1, '01-Aug-2005' UNION ALL -- All too oldSELECT 2, '02-Jan-2005' UNION ALL -- Too old, but billing OKSELECT 3, '03-Aug-2005' UNION ALL -- OK, but billing not OKSELECT 4, '04-Aug-2005' UNION ALL -- Both OKSELECT 31, '31-Dec-2005' -- All too newGOINSERT INTO billingSELECT 1, '01-Aug-2005' UNION ALL -- Too oldSELECT 2, '02-Sep-2005' UNION ALLSELECT 3, '03-Jan-2005' UNION ALL -- Too oldSELECT 31, '31-Dec-2005' -- Too newGOSELECT C.contactid, C.contractdate, B.paymentdateFROM contacts C LEFT OUTER JOIN billing B ON B.contactid = C.contactid AND paymentdate > '01-Aug-2005' AND paymentdate < '31-Dec-2005'WHERE B.contactid IS NOT NULL -- Got an OK Billing record OR ( contractdate > '01-Aug-2005' AND contractdate < '31-Dec-2005' )ORDER BY B.contactidGODROP TABLE contactsGODROP TABLE billingGO Kristen |
 |
|
|
dogtag1
Starting Member
4 Posts |
Posted - 2005-08-05 : 14:43:09
|
Thanks, that makes sense.SELECT C.contactid, C.contractdate, B.paymentdateFROM contacts C LEFT OUTER JOIN billing B ON B.contactid = C.contactid AND paymentdate > '01-Aug-2005' AND paymentdate < '31-Dec-2005'WHERE B.contactid IS NOT NULL -- Got an OK Billing record OR ( contractdate > '01-Aug-2005' AND contractdate < '31-Dec-2005' )ORDER BY B.contactid just for the sake of understanding this, how is the "AND paymentdate >...." before the where statement? and what does this do? Thanks again for the help.-Jeff |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-08-06 : 02:47:47
|
Putting the AND stuff in the LEFT OUTER JOIN means that only those rows are satisfied. If the ON / AND stuff in the JOIN doesn't match any rows then the "billing" columns come back NULL.This is just a bit more efficient, and easier, than messing around with it in the WHERE clause.So basically we get All contacts thatEITHER have a ContractDate in the rangeOR have a Billing Record in range ("B.contactid IS NOT NULL" indicates we found a billing record and, ipso facto, it must have a valid payment date)In my previous example I was trying to get things where either of the tables had a date within the range and I was also assuming that the corresponding record in the other table might, or might not , exist - bit more complicated that one!If you try to do it all in the WHERE clause you would wind up with something along the lines of:Select it:If the Contract Date is in RangeOr there exists a Billing record, and it has a PaymentDate in RangeActually not that hard now I've written it! But my guess would be that the SQL optimiser might miss the significance of the OR in that WHERE and might restort to a table scan, rather than using indexes, whereas doing it this way tells the query optimised to only hit on Billing records in the date range.Anyway, thats how I *think* it works! You could try it both ways and see what the Query Plan is - might be interesting to know if the Query Planner comes up with the exact same plan!SELECT C.contactid, C.contractdate, B.paymentdateFROM contacts C LEFT OUTER JOIN billing B ON B.contactid = C.contactidWHERE ( B.contactid IS NOT NULL -- Got a Billing record AND paymentdate > '01-Aug-2005' AND paymentdate < '31-Dec-2005' ) OR ( contractdate > '01-Aug-2005' AND contractdate < '31-Dec-2005' )ORDER BY B.contactid Kristen |
 |
|
|
|
|
|
|
|