I have two scripts which produce the following two tables(t1 and t2).
Is there a way of merging t1 and t2 to make t3?
The first 5 rows of each table have the same value in the first column (Number).
However in t1 the columns PreOpOrg and PreOpModality are populated but in t2 they are NULL, and vice versa for columns PostOpOrg and PostOpModality.
So the merge would populate the columns with the non-NULL values from each table (t1 and t2). For the rows in t1 and t2 that only appear in one table then they should appear in t3 as if a normal UNION were being attempted.
Unfortunately while I am working in SQL2005 the script needs to be compatible with SQL2000.
Many thanks.
--t1
Number DateOfBirth PreOpOrg PreOpModality PostOpOrg PostOpModality DiagDate
8643576344 01/04/1935 00:00:00 RBA11 2 NULL NULL 04/09/2012 00:00
2345680016 01/01/1960 00:00:00 RBA11 4 NULL NULL 11/11/2011 00:00
6955934252 20/01/1980 00:00:00 RBA11 4 NULL NULL 22/08/2012 00:00
2234582369 28/12/1940 00:00:00 RBA11 5 NULL NULL 02/11/2011 00:00
9477684368 01/02/1959 00:00:00 RBA11 5 NULL NULL 02/01/2014 00:00
--t2
Number DateOfBirth PreOpOrg PreOpModality PostOpOrg PostOpModality DiagDate
8643576344 01/04/1935 00:00:00 NULL NULL RBA11 2 04/09/2012 00:00
2345680016 01/01/1960 00:00:00 NULL NULL RBA11 2 11/11/2011 00:00
6955934252 20/01/1980 00:00:00 NULL NULL RN325 5 22/08/2012 00:00
2234582369 28/12/1940 00:00:00 NULL NULL RBA11 5 02/11/2011 00:00
9477684368 01/02/1959 00:00:00 NULL NULL RBA11 5 02/01/2014 00:00
0000001564 01/01/1970 00:00:00 NULL NULL RBA11 2 08/08/2012 00:00
4225127842 11/07/1948 00:00:00 NULL NULL RBA11 2 10/09/2011 00:00
0909093842 01/07/1957 00:00:00 NULL NULL RN325 5 26/08/2009 00:00
8528528855 05/12/1969 00:00:00 NULL NULL RBA11 5 25/10/2010 00:00
1000001367 05/05/1950 00:00:00 NULL NULL RBA11 5 08/04/2011 00:00
2234573513 30/11/1946 00:00:00 NULL NULL RN325 5 20/04/2011 00:00
1000001566 18/03/1951 00:00:00 NULL NULL RBA11 5 20/03/2012 00:00
0000001600 01/01/1970 00:00:00 NULL NULL RBA11 5 28/03/2013 00:00
1000001621 12/12/1950 00:00:00 NULL NULL RBA11 5 06/12/2013 00:00
--t3
Number DateOfBirth PreOpOrg PreOpModality PostOpOrg PostOpModality DiagDate
8643576344 01/04/1935 00:00:00 RBA11 2 RBA11 2 04/09/2012 00:00
2345680016 01/01/1960 00:00:00 RBA11 4 RBA11 2 11/11/2011 00:00
6955934252 20/01/1980 00:00:00 RBA11 4 RN325 5 22/08/2012 00:00
2234582369 28/12/1940 00:00:00 RBA11 5 RBA11 5 02/11/2011 00:00
9477684368 01/02/1959 00:00:00 RBA11 5 RBA11 5 02/01/2014 00:00
0000001564 01/01/1970 00:00:00 NULL NULL RBA11 2 08/08/2012 00:00
4225127842 11/07/1948 00:00:00 NULL NULL RBA11 2 10/09/2011 00:00
0909093842 01/07/1957 00:00:00 NULL NULL RN325 5 26/08/2009 00:00
8528528855 05/12/1969 00:00:00 NULL NULL RBA11 5 25/10/2010 00:00
1000001367 05/05/1950 00:00:00 NULL NULL RBA11 5 08/04/2011 00:00
2234573513 30/11/1946 00:00:00 NULL NULL RN325 5 20/04/2011 00:00
1000001566 18/03/1951 00:00:00 NULL NULL RBA11 5 20/03/2012 00:00
0000001600 01/01/1970 00:00:00 NULL NULL RBA11 5 28/03/2013 00:00
1000001621 12/12/1950 00:00:00 NULL NULL RBA11 5 06/12/2013 00:00
Considering to your data and requirement to run on SQL 2000 I am providing you below solution.
Please let me know in case you face any issue. For my convenience I have added only few records from your sample. If you are using SQL Server 2008 or higher version you can use of COALESCE function as explained here.
create table t1
(
Number VARCHAR(10),
DateOfBirth DATETIME,
PreOpOrg VARCHAR(10),
PreOpModality INT,
PostOpOrg VARCHAR(10),
PostOpModality INT,
DiagDate DATETIME
)
create table t2
(
Number VARCHAR(10),
DateOfBirth DATETIME,
PreOpOrg VARCHAR(10),
PreOpModality INT,
PostOpOrg VARCHAR(10),
PostOpModality INT,
DiagDate DATETIME
)
INSERT INTO T1 values (8643576344,'01/04/1935 00:00:00','RBA11',2,NULL,NULL,'04/09/2012 00:00'),
(2345680016,'01/01/1960 00:00:00','RBA11',4,NULL,NULL,'11/11/2011 00:00')
INSERT INTO T2 values ('8643576344','01/04/1935 00:00:00',NULL,NULL,'RBA11',2,'04/09/2012 00:00'),
('0000001564','01/01/1970 00:00:00',NULL,NULL,'RBA11',2,'08/08/2012 00:00'),
('2345680016','01/01/1960 00:00:00',NULL,NULL,'RBA11',2,'11/11/2011 00:00' )
SELECT * FROM T1
SELECT * FROM T2
SELECT CASE WHEN T1.Number IS NOT NULL THEN T1.Number ELSE T2.NUMBER END AS Number,
CASE WHEN T1.DateOfBirth IS NOT NULL THEN T1.DateOfBirth ELSE T2.DateOfBirth END AS DateOfBirth,
CASE WHEN T1.PreOpOrg IS NOT NULL THEN T1.PreOpOrg ELSE T2.PreOpOrg END AS PreOpOrg,
CASE WHEN T1.PreOpModality IS NOT NULL THEN T1.PreOpModality ELSE T2.PreOpModality END AS PreOpModality,
CASE WHEN T1.PostOpOrg IS NOT NULL THEN T1.PostOpOrg ELSE T2.PostOpOrg END AS PostOpOrg,
CASE WHEN T1.PostOpModality IS NOT NULL THEN T1.PostOpModality ELSE T2.PostOpModality END AS PostOpModality,
CASE WHEN T1.DiagDate IS NOT NULL THEN T1.DiagDate ELSE T2.DiagDate END AS DiagDate
FROM T1
RIGHT JOIN T2 ON T1.Number = T2.Number
Another solution can be
SELECT
ISNULL(T1.Number, T2.NUMBER) AS Number
,ISNULL(T1.DateOfBirth, T2.DateOfBirth) AS DateOfBirth
,ISNULL(T1.PreOpOrg, T2.PreOpOrg) AS PreOpOrg
,ISNULL(T1.PreOpModality, T2.PreOpModality) AS PreOpModality
,ISNULL(T1.PostOpOrg, T2.PostOpOrg) AS PostOpOrg
,ISNULL(T1.PostOpModality, T2.PostOpModality) AS PostOpModality
,ISNULL(T1.DiagDate, T2.DiagDate) AS DiagDate
FROM T1
RIGHT JOIN T2
ON T1.Number = T2.Number
Related
I have this SQL-SERVER Query:
SELECT t.Id,
t.ClientTemplateFieldId,
t.ClientTemplateFieldOptionId,
t.TextData,
t.NumberData,
t.DateTimeData,
t.TreatmentDate,
t.rn FROM
(
SELECT tfd.Id,
tfd.ClientTemplateFieldId,
tfd.ClientTemplateFieldOptionId,
tfd.TextData,
tfd.NumberData,
tfd.DateTimeData,
t.TreatmentDate,
ROW_NUMBER() OVER (PARTITION BY tfd.ClientTemplateFieldId ORDER BY t.TreatmentDate DESC) as rn
FROM TemplateFieldData tfd
INNER JOIN
Treatment t ON tfd.TreatmentId = t.Id
WHERE tfd.IsDeleted = 0 AND
t.IsDeleted = 0 AND
tfd.ClientId = 2 AND
t.ClientId = 2 AND
t.PatientId = 6003720 AND
tfd.ClientTemplateFieldId IN
(1873,1874,1875,1876)
) AS t
--WHERE CLAUSE...
And this is the table result of the above query:
Id ClientTemplateFieldId ClientTemplateFieldOptionId TextData NumberData DateTimeData TreatmentDate rn
4324 1873 1627 NULL NULL NULL 2021-01-14 09:00:00.000 1
4325 1873 1628 NULL NULL NULL 2021-01-14 09:00:00.000 2
4326 1873 1631 NULL NULL NULL 2021-01-14 09:00:00.000 3
4322 1873 1627 NULL NULL NULL 2021-01-13 09:00:00.000 4
4323 1873 1629 NULL NULL NULL 2021-01-13 09:00:00.000 5
4320 1873 1626 NULL NULL NULL 2021-01-12 22:00:00.000 6
4321 1873 1630 NULL NULL NULL 2021-01-12 22:00:00.000 7
4338 1874 NULL SomeTxt NULL NULL 2021-01-14 09:00:00.000 1
4330 1874 NULL SomeTxt NULL NULL 2021-01-13 09:00:00.000 2
4327 1874 NULL SomeTxt NULL NULL 2021-01-12 22:00:00.000 3
4328 1875 NULL NULL 10.00 NULL 2021-01-12 22:00:00.000 1
4331 1876 1634 NULL NULL NULL 2021-01-13 09:00:00.000 1
4329 1876 1632 NULL NULL NULL 2021-01-12 22:00:00.000 2
What should I put in the Where Clause in order to retrieve all rows with row_number = 1 and
also if there is a row with the same TreatmentDate and ClientTemplateFieldId as of one of the rows where
row_number = 1, I need that row to.
Meaning I need this result:
Id ClientTemplateFieldId ClientTemplateFieldOptionId TextData NumberData DateTimeData TreatmentDate rn
4324 1873 1627 NULL NULL NULL 2021-01-14 09:00:00.000 1
4325 1873 1628 NULL NULL NULL 2021-01-14 09:00:00.000 2
4326 1873 1631 NULL NULL NULL 2021-01-14 09:00:00.000 3
4338 1874 NULL SomeTxt NULL NULL 2021-01-14 09:00:00.000 1
4328 1875 NULL NULL 10.00 NULL 2021-01-12 22:00:00.000 1
4331 1876 1634 NULL NULL NULL 2021-01-13 09:00:00.000 1
You could use MAX() window function instead of ROW_NUMBER() to get all the rows with the latest TreatmentDate for each ClientTemplateFieldId:
SELECT t.Id,
t.ClientTemplateFieldId,
t.ClientTemplateFieldOptionId,
t.TextData,
t.NumberData,
t.DateTimeData,
t.TreatmentDate,
t.rn
FROM (
SELECT tfd.Id,
tfd.ClientTemplateFieldId,
tfd.ClientTemplateFieldOptionId,
tfd.TextData,
tfd.NumberData,
tfd.DateTimeData,
t.TreatmentDate,
ROW_NUMBER() OVER (PARTITION BY tfd.ClientTemplateFieldId ORDER BY t.TreatmentDate DESC) AS rn,
MAX(t.TreatmentDate) OVER (PARTITION BY tfd.ClientTemplateFieldId) AS max_TreatmentDate
FROM TemplateFieldData tfd
INNER JOIN
Treatment t ON tfd.TreatmentId = t.Id
WHERE tfd.IsDeleted = 0 AND
t.IsDeleted = 0 AND
tfd.ClientId = 2 AND
t.ClientId = 2 AND
t.PatientId = 6003720 AND
tfd.ClientTemplateFieldId IN
(1873,1874,1875,1876)
) AS t
WHERE t.TreatmentDate = t.max_TreatmentDate
ROW_NUMBER() is not actually needed but I kept it in my query just in case you want it in the results.
If I assume that this entire query result (without the where condition) is created as a View called T for example, you can do the following:
SELECT *
FROM T
WHERE T.rn = 1
OR EXISTS
(SELECT 1 FROM T as T2
WHERE T2.TreatmentDate = T.TreatmentDate
AND T2.ClientTemplateFieldId = T.ClientTemplateFieldId
AND T.rn != 1
AND T2.rn = 1)
I´m having trouble identifying who to fix this simple join.
SELECT A.CUSER,
COUNT(*) AS QTD
FROM BO_PRODUCTCONFIG A WITH (NOLOCK)
INNER JOIN BO_PRICER001 B WITH (NOLOCK)
ON (
A.CIDBRANCH = B.CIDBRANCH
OR B.CIDBRANCH IS NULL
)
AND (
A.CIDPRODUCT = B.CIDPRODUCT
OR B.CIDPRODUCT IS NULL
)
My problem is, after adding the column B.CIDPRODUCT IS NULL this query takes hours to finish.
table BO_PRICER001 rows 286537
table BO_PRODUCTCONFIG rows 7934844
on the table BO_PRICER001 exists 15329 rows with null
with B.CIDPRODUCT IS NULL the live query show this plan:
and without this column the plan is:
I already try to force an index and switch to a subquery but the problem continues.
if possible, I really appreciate a help.
Sample of data from PRICER001
CIDPRICE CIDCOMPANY CIDBRANCH CIDTABLEPRICE CIDCOMMISSIONGROUP CIDPRODUCT CIDPERIODPAYMENT DENDDATEVALIDITY DSTARTDATEVALIDITY NINCREASEPERCENT LACTIVE DLASTUPDATE NINCREASEPERCENTORIG
XPTO0319 XPTO NULL NULL NULL NULL 319 9999-12-31 00:00:00.000 2018-08-27 00:00:00.000 2.100 1 2020-10-07 05:07:37.917 21.000
XPTO0321 XPTO NULL NULL NULL NULL 321 9999-12-31 00:00:00.000 2014-08-06 00:00:00.000 2.100 1 2020-10-07 05:07:37.917 21.000
XPTO0326 XPTO NULL NULL NULL NULL 326 9999-12-31 00:00:00.000 2018-08-27 00:00:00.000 3.150 1 2020-10-07 05:07:37.917 31.500
XPTO0328 XPTO NULL NULL NULL NULL 328 9999-12-31 00:00:00.000 2014-08-06 00:00:00.000 3.150 1 2020-10-07 05:07:37.917 31.500
XPTO0345 XPTO NULL NULL NULL NULL 345 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 4.530 1 2020-10-07 05:07:37.917 45.300
XPTO0390 XPTO NULL NULL NULL NULL 390 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 9.130 1 2020-10-07 05:07:37.917 91.300
XPTO0412 XPTO NULL NULL NULL NULL 412 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 11.500 1 2020-10-07 05:07:37.917 115.000
XPTO0428 XPTO NULL NULL NULL NULL 428 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 2.640 1 2020-10-07 05:07:37.917 26.400
XPTO0460 XPTO NULL NULL NULL NULL 460 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 5.690 1 2020-10-07 05:07:37.917 56.900
XPTO0515 XPTO NULL NULL NULL NULL 515 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 13.900 1 2020-10-07 05:07:37.917 139.000
Sample of data from PRODUCTCONFIG
CIDPRODUCTCONFIG CIDPRODUCT CIDPRODUCTMARKET CIDPRODUCTBUSINESS CIDPRODUCTLINE CIDPRODUCTGROUP CIDPRODUCTSUBGROUP CIDREGION CIDBRANCH CIDTEAM CIDTERRITORY LACTIVE LFLAG DLASTUPDATE CUSER CTPDCA
5840992036 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2036 1 NULL 2020-10-07 00:49:15.837 2036 1
5840992037 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2037 1 NULL 2020-10-07 00:49:15.837 2037 1
5840992038 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2038 1 NULL 2020-10-07 00:49:15.837 2038 1
5840992039 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2039 1 NULL 2020-10-07 00:49:15.837 2039 1
5840992040 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2040 1 NULL 2020-10-07 00:49:15.837 2040 1
5840992041 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2041 1 NULL 2020-10-07 00:49:15.837 2041 1
5840992042 584099 XPTO XPTO XPTO ACM FFK NULL 1402 NULL 2042 1 NULL 2020-10-07 00:18:20.783 2042 1
5840992044 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2044 1 NULL 2020-10-07 00:49:15.837 2044 1
5840992045 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2045 1 NULL 2020-10-07 00:49:15.837 2045 1
5840992048 584099 XPTO XPTO XPTO ACM FFK NULL 1686 NULL 2048 1 NULL 2020-10-07 00:50:20.223 2048 1
OR kills performance. A typical workaround are multiple LEFT JOIN. Perhaps:
I´m having trouble identifying who to fix this simple join.
SELECT pc.CUSER,
COUNT(*) AS QTD
FROM BO_PRODUCTCONFIG pc LEFT JOIN
BO_PRICER001 prbp
ON pc.CIDBRANCH = prbp.CIDBRANCH AND
pc.CIDPRODUCT = prbp.CIDPRODUCT LEFT JOIN
BO_PRICER001 prb
ON pc.CIDBRANCH = prb.CIDBRANCH AND
prbp.CIDPRODUCT IS NULL LEFT JOIN
BO_PRICER001 prp
ON prp.CIDBRANCH IS NULL AND
prp.CIDPRODUCT = pc.CIDPRODUCT LEFT JOIN
BO_PRICER001 pr
ON prp.CIDBRANCH IS NULL AND
prp.CIDPRODUCT IS NULL
WHERE prbp.CIDBRANCH is not null OR prb.CIDBRANCH is not null OR pr.CIDPRODUCT is not null or pr.<some other column> is not null;
ActivateDate ShipDate Month Month_Length Day-2c Day-2c_Length YEAR-201x SHIPDateConcatenate ActivateDateConcatenate
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
NULL 6/12/2018 12:00:00 AM 6 1 12 2 2018 6-12-2018 NULL
10/12/2018 14:45 10/16/2018 12:00:00 AM 10 2 16 2 2018 10-16-2018 10-12-2018
The two columns [ActivateDate] and [ShipDate] datatype is listed below; however each time I try to use convert() or cast() to a date type, a conversion error occurs.
SELECT
[ActivateDate], -- '10/12/2018 14:45' nvarchar(100)
[ShipDate], -- '6/12/2018 12:00:00 AM' nvarchar(100)
SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/', iedimpr.[ShipDate])-2,2) as 'Month',
LEN(SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/', iedimpr.[ShipDate])-2,2)) as 'Month_Length',
REPLACE(SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/', iedimpr.[ShipDate])+1,2),'/','') as 'Day-2c',
LEN(REPLACE(SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/', iedimpr.[ShipDate])+1,2),'/','')) as 'Day-2c_Length',
SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/201', iedimpr.[ShipDate])+1,4) as 'YEAR-201x',
SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/', iedimpr.[ShipDate])-2,2)
+'-'+REPLACE(SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/', iedimpr.[ShipDate])+1,2),'/','')
+'-'+SUBSTRING(iedimpr.[ShipDate],CHARINDEX('/201', iedimpr.[ShipDate])+1,4) as 'SHIPDateConcatenate',
SUBSTRING(iedimpr.[ActivateDate],CHARINDEX('/', iedimpr.[ActivateDate])-2,2)
+'-'+REPLACE(SUBSTRING(iedimpr.[ActivateDate],CHARINDEX('/', iedimpr.[ActivateDate])+1,2),'/','')
+'-'+SUBSTRING(iedimpr.[ActivateDate],CHARINDEX('/201', iedimpr.[ActivateDate])+1,4) as 'ActivateDateConcatenate'
After reading the question again I've noticed the sample data is ill-formatted, so I've edited it. During this edit I found that you are using american style (mm/dd/yyyy) for your string representation of dates.
To convert a valid string representation of DateTime with this format into date, you need to use 101 as the style parameter in the convert method.
However, I highly recommend using Try_convert instead of Convert, since it will simply return null when the value can't be converted instead of raising an error.
That being said, here is an example:
First, create and populate sample data(Please save us this step in your future questions):
DECLARE #T AS TABLE
(
ActivateDate nvarchar(100),
ShipDate nvarchar(100)
)
INSERT INTO #T(ActivateDate, ShipDate) VALUES
(NULL, '6/12/2018 12:00:00 AM'),
('10/12/2018 14:45', '10/16/2018 12:00:00 AM'),
('20/14/2018 14:45', '10/16/2018 12:00:00 AM'), -- invalid ActivateDate
('2/4/2018 14:45', '10/16/ZOIB 12:00:00 AM') -- invalid ShipDate
The query:
SELECT ActivateDate,
ShipDate,
TRY_CONVERT(datetime, ActivateDate, 101) As DateActiveDate,
TRY_CONVERT(datetime, ShipDate, 101) As DateShipDate
FROM #T
Results:
ActivateDate ShipDate DateActiveDate DateShipDate
NULL 6/12/2018 12:00:00 AM NULL 12.06.2018 00:00:00
10/12/2018 14:45 10/16/2018 12:00:00 AM 12.10.2018 14:45:00 16.10.2018 00:00:00
20/14/2018 14:45 10/16/2018 12:00:00 AM NULL 16.10.2018 00:00:00
2/4/2018 14:45 10/16/ZOIB 12:00:00 AM 04.02.2018 14:45:00 NULL
If you only need Date (without the time part), simply use try_convert(date, ...) instead of try_convert(datetime, ...).
I have a query that looks at data that has been inserted into a TEMP table (not including as there is sensitive information in that table).
I can get the information I need, but I need to organize it better.
The output data displays as
trac_id CONTACT_DATE
040 2017-02-20 00:00:00.000
059 2017-03-08 00:00:00.000
001 2017-03-01 00:00:00.000
001 2017-03-08 00:00:00.000
001 2017-03-13 00:00:00.000
001 2017-03-16 00:00:00.000
001 2017-03-16 00:00:00.000
001 2017-03-17 00:00:00.000
001 2017-03-22 00:00:00.000
001 2017-03-23 00:00:00.000
001 2017-03-23 00:00:00.000
001 2017-03-24 00:00:00.000
001 2017-03-27 00:00:00.000
001 2017-03-27 00:00:00.000
001 2017-03-30 00:00:00.000
001 2017-03-31 00:00:00.000
068 2017-02-13 00:00:00.000
067 2017-01-24 00:00:00.000
060 2017-02-08 00:00:00.000
060 2017-03-07 00:00:00.000
011 2017-02-16 00:00:00.000
011 2017-03-01 00:00:00.000
011 2017-03-23 00:00:00.000
011 2017-03-30 00:00:00.000
005 2017-02-16 00:00:00.000
005 2017-03-18 00:00:00.000
005 2017-03-08 00:00:00.000
013 2017-03-08 00:00:00.000
013 2017-03-13 00:00:00.000
013 2017-03-16 00:00:00.000
013 2017-03-16 00:00:00.000
013 2017-03-17 00:00:00.000
013 2017-03-22 00:00:00.000
013 2017-03-23 00:00:00.000
013 2017-03-24 00:00:00.000
013 2017-03-27 00:00:00.000
013 2017-03-27 00:00:00.000
013 2017-03-30 00:00:00.000
013 2017-03-30 00:00:00.000
013 2017-03-31 00:00:00.000
043 2017-02-03 00:00:00.000
Right now I'm using the following query to get this:
SELECT
spl.trac_id
,pev.CONTACT_DATE
FROM
#SAMHSA_PAT_LIST spl
INNER JOIN dbo.IDENTITY_ID_VIEW iiv
ON iiv.IDENTITY_ID=spl.MRN
LEFT JOIN dbo.PAT_ENC_VIEW pev
ON pev.PAT_ID = iiv.PAT_ID
LEFT JOIN dbo.PAT_ENC_RSN_VISIT_VIEW rsn
ON rsn.PAT_ENC_CSN_ID=pev.PAT_ENC_CSN_ID
WHERE
pev.CONTACT_DATE >= #Start_Date
AND pev.CONTACT_DATE < #End_Date
AND pev.APPT_STATUS_C IN ( 2 , 6 , 8 , 9 )
AND rsn.ENC_REASON_ID = 590;
What I need to get is to have 2+n columns. I won't know exactly how many but a quick look shows trac_id 001 with 14 entries. So if that was the max number I would need the columns to be trac_id, mm_1, mm_2, mm_3, mm_4,...,mm_14 without hard coding the number of columns I want to PIVOT into. My problem is that in all of the posts and documentation I've seen about using PIVOT I see the data inserted into a table beforehand and then usually the entire table is PIVOT'ed.
Is it possible to only PIVOT the second column and if so, how would I do this?
So, I was able to figure out part of my solution based on a couple posts and your help #Jakub_Ojmucianski. What I've come up with is the following, but it's only halfway there and I'm sure I've made a mistake:
DECLARE #SQL VARCHAR(MAX)='',#PVT_COL VARCHAR(MAX)='';
SELECT #PVT_COL =#PVT_COL + '[mm_'+CAST(ROW_NUMBER() OVER(ORDER BY (SELECT
1)) AS VARCHAR(4))+'],'
FROM #medmtemp
SELECT #PVT_COL = LEFT(#PVT_COL,LEN(#PVT_COL)-1)
SELECT #SQL =
'SELECT * FROM (
SELECT trac_id, Contact ,''mm_''+CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1))
AS VARCHAR(4)) AS COL_NME
FROM #medmtemp
)AS A
PIVOT
(
MAX(Contact) FOR COL_NME IN ('+#PVT_COL+')
)PVT'
EXEC (#SQL)
I see the following (Just including the first three new rows):
trac_id mm_1 mm_2 mm_3 mm_4 mm_5 mm_6 mm_7 mm_8 mm_9 mm_10 mm_11 mm_12 mm_13 mm_14 mm_15 mm_16 mm_17 mm_18 mm_19 mm_20
1 3/1/2017 3/8/2017 3/13/2017 3/16/2017 3/16/2017 3/17/2017 3/22/2017 3/23/2017 3/23/2017 3/24/2017 3/27/2017 3/27/2017 3/30/2017 3/31/2017 NULL NULL NULL NULL NULL NULL
5 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 2/16/2017 3/18/2017 3/8/2017 NULL NULL NULL
8 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 3/8/2017 3/23/2017 3/30/2017
you can do something like that:
IF(OBJECT_ID('tempdb..#myTable') IS NOT null)
DROP TABLE #myTable
IF(OBJECT_ID('tempdb..#pivotColumn') IS NOT null)
DROP TABLE #pivotColumn
CREATE TABLE #myTable
(
trac_id varchar(3),
CONTACT_DATE datetime
)
INSERT INTO #myTable VALUES
('040', '2017-02-20 00:00:00.000'),
('059' ,'2017-03-08 00:00:00.000'),
('001' ,'2017-03-01 00:00:00.000'),
('001' ,'2017-03-08 00:00:00.000'),
('001' ,'2017-03-13 00:00:00.000'),
('001' ,'2017-03-16 00:00:00.000'),
('001' ,'2017-03-17 00:00:00.000')
SELECT ROW_NUMBER() OVER(ORDER BY CONTACT_DATE) as rowNumber,CONTACT_DATE INTO #pivotColumn FROM(
SELECT DISTINCT CONTACT_DATE FROM #myTable
) AS source
DECLARE #columns VARCHAR(MAX)=''
DECLARE #curentRow int = 1;
WHILE #curentRow <= (SELECT MAX(rowNumber) from #pivotColumn)
BEGIN
SET #columns+= '['+(SELECT Cast(CONTACT_DATE as varchar) FROM #pivotColumn WHERE rowNumber = #curentRow)+'],'
SET #curentRow += 1;
END
SET #columns = SUBSTRING(#columns,1,LEN(#columns)-1)
DECLARE #code Varchar(MAX) =
'
SELECT * FROM #myTable
Pivot
(
COUNT(trac_id) FOR CONTACT_DATE IN (
'
+
#columns
+
'
)
) as p'
EXEC(#code)
But be aware of grouping function in dynamic pivot - you have to decide what you want to do with those data? Sum it, count it?
Regards
I have two SQL Server tables containing the following information:
Table t_venues:
venue_id is unique
venue_id | start_date | end_date
1 | 01/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 15/01/2014
4 | 20/01/2014 | 30/01/2014
Table t_venueuser:
venue_id is not unique
venue_id | start_date | end_date
1 | 02/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 10/01/2014
4 | 23/01/2014 | 25/01/2014
From these two tables I need to find the dates that haven't been selected for each range, so the output would look like this:
venue_id | start_date | end_date
1 | 01/01/2014 | 01/01/2014
3 | 11/01/2014 | 15/01/2014
4 | 20/01/2014 | 22/01/2014
4 | 26/01/2014 | 30/01/2014
I can compare the two tables and get the date ranges from t_venues to appear in my query using 'except' but I can't get the query to produce the non-selected dates. Any help would be appreciated.
Calendar Table!
Another perfect candidate for a calendar table. If you can't be bothered to search for one, here's one I made earlier.
Setup Data
DECLARE #t_venues table (
venue_id int
, start_date date
, end_date date
);
INSERT INTO #t_venues (venue_id, start_date, end_date)
VALUES (1, '2014-01-01', '2014-01-02')
, (2, '2014-01-05', '2014-01-05')
, (3, '2014-01-09', '2014-01-15')
, (4, '2014-01-20', '2014-01-30')
;
DECLARE #t_venueuser table (
venue_id int
, start_date date
, end_date date
);
INSERT INTO #t_venueuser (venue_id, start_date, end_date)
VALUES (1, '2014-01-02', '2014-01-02')
, (2, '2014-01-05', '2014-01-05')
, (3, '2014-01-09', '2014-01-10')
, (4, '2014-01-23', '2014-01-25')
;
The Query
SELECT t_venues.venue_id
, calendar.the_date
, CASE WHEN t_venueuser.venue_id IS NULL THEN 1 ELSE 0 END As is_available
FROM dbo.calendar /* see: http://gvee.co.uk/files/sql/dbo.numbers%20&%20dbo.calendar.sql for an example */
INNER
JOIN #t_venues As t_venues
ON t_venues.start_date <= calendar.the_date
AND t_venues.end_date >= calendar.the_date
LEFT
JOIN #t_venueuser As t_venueuser
ON t_venueuser.venue_id = t_venues.venue_id
AND t_venueuser.start_date <= calendar.the_date
AND t_venueuser.end_date >= calendar.the_date
ORDER
BY t_venues.venue_id
, calendar.the_date
;
The Result
venue_id the_date is_available
----------- ----------------------- ------------
1 2014-01-01 00:00:00.000 1
1 2014-01-02 00:00:00.000 0
2 2014-01-05 00:00:00.000 0
3 2014-01-09 00:00:00.000 0
3 2014-01-10 00:00:00.000 0
3 2014-01-11 00:00:00.000 1
3 2014-01-12 00:00:00.000 1
3 2014-01-13 00:00:00.000 1
3 2014-01-14 00:00:00.000 1
3 2014-01-15 00:00:00.000 1
4 2014-01-20 00:00:00.000 1
4 2014-01-21 00:00:00.000 1
4 2014-01-22 00:00:00.000 1
4 2014-01-23 00:00:00.000 0
4 2014-01-24 00:00:00.000 0
4 2014-01-25 00:00:00.000 0
4 2014-01-26 00:00:00.000 1
4 2014-01-27 00:00:00.000 1
4 2014-01-28 00:00:00.000 1
4 2014-01-29 00:00:00.000 1
4 2014-01-30 00:00:00.000 1
(21 row(s) affected)
The Explanation
Our calendar tables contains an entry for every date.
We join our t_venues (as an aside, if you have the choice, lose the t_ prefix!) to return every day between our start_date and end_date. Example output for venue_id=4 for just this join:
venue_id the_date
----------- -----------------------
4 2014-01-20 00:00:00.000
4 2014-01-21 00:00:00.000
4 2014-01-22 00:00:00.000
4 2014-01-23 00:00:00.000
4 2014-01-24 00:00:00.000
4 2014-01-25 00:00:00.000
4 2014-01-26 00:00:00.000
4 2014-01-27 00:00:00.000
4 2014-01-28 00:00:00.000
4 2014-01-29 00:00:00.000
4 2014-01-30 00:00:00.000
(11 row(s) affected)
Now we have one row per day, we [outer] join our t_venueuser table. We join this in much the same manner as before, but with one added twist: we need to join based on the venue_id too!
Running this for venue_id=4 gives this result:
venue_id the_date t_venueuser_venue_id
----------- ----------------------- --------------------
4 2014-01-20 00:00:00.000 NULL
4 2014-01-21 00:00:00.000 NULL
4 2014-01-22 00:00:00.000 NULL
4 2014-01-23 00:00:00.000 4
4 2014-01-24 00:00:00.000 4
4 2014-01-25 00:00:00.000 4
4 2014-01-26 00:00:00.000 NULL
4 2014-01-27 00:00:00.000 NULL
4 2014-01-28 00:00:00.000 NULL
4 2014-01-29 00:00:00.000 NULL
4 2014-01-30 00:00:00.000 NULL
(11 row(s) affected)
See how we have a NULL value for rows where there is no t_venueuser record. Genius, no? ;-)
So in my first query I gave you a quick CASE statement that shows availability (1=available, 0=not available). This is for illustration only, but could be useful to you.
You can then either wrap the query up and then apply an extra filter on this calculated column or simply add a where clause in: WHERE t_venueuser.venue_id IS NULL and that will do the same trick.
This is a complete hack, but it gives the results you require, I've only tested it on the data you provided so there may well be gotchas with larger sets.
In general what you are looking at solving here is a variation of gaps and islands problem ,this is (briefly) a sequence where some items are missing. The missing items are referred as gaps and the existing items are referred as islands. If you would like to understand this issue in general check a few of the articles:
Simple talk article
blogs.MSDN article
SO answers tagged gaps-and-islands
Code:
;with dates as
(
SELECT vdates.venue_id,
vdates.vdate
FROM ( SELECT DATEADD(d,sv.number,v.start_date) vdate
, v.venue_id
FROM t_venues v
INNER JOIN master..spt_values sv
ON sv.type='P'
AND sv.number BETWEEN 0 AND datediff(d, v.start_date, v.end_date)) vdates
LEFT JOIN t_venueuser vu
ON vdates.vdate >= vu.start_date
AND vdates.vdate <= vu.end_date
AND vdates.venue_id = vu.venue_id
WHERE ISNULL(vu.venue_id,-1) = -1
)
SELECT venue_id, ISNULL([1],[2]) StartDate, [2] EndDate
FROM (SELECT venue_id, rDate, ROW_NUMBER() OVER (PARTITION BY venue_id, DateType ORDER BY rDate) AS rType, DateType as dType
FROM( SELECT d1.venue_id
,d1.vdate AS rDate
,'1' AS DateType
FROM dates AS d1
LEFT JOIN dates AS d0
ON DATEADD(d,-1,d1.vdate) = d0.vdate
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 1
AND ISNULL(d0.vdate, '01 Jan 1753') = '01 Jan 1753'
UNION
SELECT d1.venue_id
,ISNULL(d2.vdate,d1.vdate)
,'2'
FROM dates AS d1
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 2
) res
) src
PIVOT (MIN (rDate)
FOR dType IN
( [1], [2] )
) AS pvt
Results:
venue_id StartDate EndDate
1 2014-01-01 2014-01-01
3 2014-01-11 2014-01-15
4 2014-01-20 2014-01-22
4 2014-01-26 2014-01-30