Comparing ODI scenarios development vs production - oracle-data-integrator

I have a list of interfaces, I want to update some mappings in these interfaces but unfortunately our Production and Development environments are not synchronized.
So before editing any interfaces, we need to compare DEV and PROD environments to see, if there is any difference. For some small jobs it is easy to do it manually. But in my case there are more than 100 interfaces and I want to somewhat automatize this process. I need some suggestions on that.
Any help will be appreciated.
Thanks

Use this query against the repository
-- Repository_Object_Changed_by_date -- Here my Work repository User is ODI_WORK_REPO -- ODI version 11 g
WITH obj as(
SELECT i_package i_instance, i_folder, NULL i_project, pack_name obj_name,3200 obj_type, 'Package' obj_type_name, last_date, last_user FROM ODI_WORK_REPO.SNP_PACKAGE
UNION ALL
SELECT i_pop i_instance, i_folder, NULL i_project, pop_name obj_name,3100 obj_type, 'Interface' obj_type_name, last_date, last_user FROM ODI_WORK_REPO.SNP_POP
UNION ALL
SELECT i_trt i_instance, i_folder, i_project, trt_name obj_name,3600 obj_type, CASE trt_type WHEN 'U' THEN 'Procedure' ELSE 'Knowledge Module' END obj_type_name, last_date, last_user FROM ODI_WORK_REPO.SNP_TRT
UNION ALL
SELECT i_var i_instance, NULL i_folder, i_project, var_name obj_name, 3500 obj_type, 'Variable' obj_type_name, last_date, last_user FROM ODI_WORK_REPO.SNP_VAR t
UNION ALL
SELECT i_table i_instance, i_sub_model i_folder, i_mod i_project, table_name obj_name, 2400 obj_type, 'Table' obj_type_name, last_date, last_user from ODI_WORK_REPO.snp_table t
)
,fd (i_folder, i_project, folder_name, folder_path, lv) AS(
SELECT i_folder, i_project, folder_name, folder_name folder_path, 1 lv
FROM ODI_WORK_REPO.snp_folder
WHERE par_i_folder IS NULL
UNION ALL
SELECT tf.i_folder, tf.i_project, tf.folder_name, fd.folder_path||'\'||tf.folder_name, fd.lv+1
FROM ODI_WORK_REPO.snp_folder tf JOIN fd
ON fd.i_folder = tf.par_i_folder
)
,mpl as (
SELECT sm.i_smod i_mc, 'sm' typemc, COALESCE(sm.i_smod_parent,sm.i_mod) i_mp, NVL2(sm.i_smod_parent,'sm','m') typemp, sm.smod_name name --, m.i_mod_folder
FROM ODI_WORK_REPO.snp_sub_model sm
UNION ALL
SELECT i_mod, 'm' typ, i_mod_folder, 'mf', mod_name
FROM ODI_WORK_REPO.snp_model m
UNION ALL
SELECT i_mod_folder, 'mf', par_i_mod_folder, 'mf', mod_folder_name FROM ODI_WORK_REPO.snp_mod_folder
)
,mp (i_mc, typemc, i_mp, typemp, model_tech, model_path, lv) AS(
SELECT i_mc, typemc, i_mp, typemp, name tname, name model_path, 1 lv
FROM mpl
WHERE i_mp IS NULL
UNION ALL
SELECT mpl.i_mc, mpl.typemc, mpl.i_mp, mpl.typemp, mp.model_tech, mp.model_path||'\'||mpl.name model_path, mp.lv+1 lv
FROM mpl JOIN mp
ON mpl.i_mp = mp.i_mc AND mpl.typemp=mp.typemc
)
SELECT obj.i_instance, OBJ_NAME, CASE WHEN COALESCE(project_name,mp.model_tech) IS NULL THEN 'Global ' || OBJ_TYPE_NAME ELSE OBJ_TYPE_NAME END obj_type_name
,obj.last_date
,obj.last_user
,COALESCE(project_name,mp.model_tech) project_model
,COALESCE(fd.folder_path,mp.model_path) path
FROM obj
FULL OUTER
JOIN fd
ON fd.i_folder = obj.i_folder AND obj_type_name!='Table'
FULL OUTER
JOIN mp
ON mp.i_mc = obj.i_folder AND obj_type_name='Table'
FULL OUTER
JOIN ODI_WORK_REPO.snp_project p
ON p.i_project = COALESCE(obj.i_project, fd.i_project)
FULL OUTER
JOIN ODI_WORK_REPO.snp_model m
ON m.i_mod = obj.i_project

Related

SQL Server - View that contains a TOP 1 select column

I have a customer table, and then there's a separate transactional table that cross-references the customer table. With one particular column that I would like to present to the consumer as a combined SQL view. This transactional column is referred to as LastEdited.
The view itself is fine, if I run SELECT statements by querying columns like FirstName, LastName, etc. Where I run into issues is when querying the LastEdited column. This column is using a TOP 1 select criteria. For example, if I query LastEdited BETWEEN '1/1/2019 00:00:01' and '6/30/2019 23:59:59'. The results take a long time, since there are obvious performance penalties.
Any suggestions on how best to handle this? I've tried creating the column for this view by invoking a scalar function, like:
(select dbo.fncUser_LastCustomerEditDate(c.CustomerNo)) as LastEdited
This scalar function basically returns the TOP 1 record. I've also tried creating the column by referencing it against an OUTER APPLY, like:
...OUTER APPLY (SELECT top 1 GMTTimestamp from dbo.tbl121_DataLog dl where dl.PrimaryKey = c.Id and dl.DBActionId In (600001, 600002) order by dl.GMTTimeStamp DESC) dl
so that my SELECT list just looks at:
dl.GMTTimeStamp as LastEdited
Neither option provides me the ability to quickly return results by querying the resultant view based on this column.
Any help or suggestions would be appreciated!
Here are the two view constructions I've tried so far:
CREATE VIEW [dbo].[viwUser_Customers_Custom2]
AS
SELECT c.Id, c.Type, c.CustomerNo, sit.Code AS PrimarySiteCode, sit.Name AS PrimarySiteName, emp.Code AS PrimarySalespersonCode,
emp.Name AS PrimarySalespersonName, c.Title, c.FirstName, c.MiddleName, c.LastName, c.NickName, c.Greeting, c.PreviousName,
dbo.fncCustContactMethodText(c.PreferredContactMethod) AS PreferredContactMethod, cad.Address1, cad.Address2, cad.Address3, cad.City, cad.State,
cad.PostCode, cad.Country, cpp.CountryPrefix AS PhoneCountryPrefix, cpp.AreaCode AS PhoneAreaCode, cpp.Number AS PhoneNumber,
cpp.Extension AS PhoneExtension, dbo.fncCustFormattedPhoneNo(cpp.CountryPrefix, cpp.AreaCode, cpp.Number, cpp.Extension)
AS PhoneNumberFormatted, cpf.CountryPrefix AS FaxCountryPrefix, cpf.AreaCode AS FaxAreaCode, cpf.Number AS FaxNumber,
cpf.Extension AS FaxExtension, dbo.fncCustFormattedPhoneNo(cpf.CountryPrefix, cpf.AreaCode, cpf.Number, cpf.Extension) AS FaxNumberFormatted,
cpm.CountryPrefix AS MobileCountryPrefix, cpm.AreaCode AS MobileAreaCode, cpm.Number AS MobileNumber, cpm.Extension AS MobileExtension,
dbo.fncCustFormattedPhoneNo(cpm.CountryPrefix, cpm.AreaCode, cpm.Number, cpm.Extension) AS MobileNumberFormatted, cpe.EmailAddress, c.Sex,
c.UDFList1, c.UDFList2, c.UDFList3, c.UDFList4, c.UDFList5, c.UDFList6, c.UDFList7, c.UDFList8, c.UDFList9, c.UDFList10, c.UDFList11, c.UDFList12,
c.FingerSize1 AS LeftLittleFingerSize, c.FingerSize2 AS LeftRingFingerSize, c.FingerSize3 AS LeftMiddleFingerSize,
c.FingerSize4 AS LeftIndexFingerSize, c.FingerSize5 AS LeftThumbSize, c.FingerSize6 AS RightThumbSize, c.FingerSize7 AS RightIndexFingerSize,
c.FingerSize8 AS RightMiddleFingerSize, c.FingerSize9 AS RightRingFingerSize, c.FingerSize10 AS RightLittleFingerSize, c.LeftWristSize,
c.RightWristSize, c.NeckSize, c.SocSecNumber, c.POSComments, c.SecureComments, c.Status, c.Active, c.Day, c.Month, c.Year, dbo.fncGetDOB(c.Day,
c.Month, c.Year) AS BirthDate, dbo.fncGetAge(c.Day, c.Month, c.Year, c.Age, c.AgeReferenceDate, GETDATE()) AS Age, CAST('' AS varchar(1000))
AS MailingName, CAST('' AS varchar(1000)) AS GreetingName, CAST(0 AS money) AS CustomerSalesTotalForDateRange, CAST(0 AS money)
AS CustomerSalesTotal, CAST('' AS varchar(50)) AS PartnerCustomerNo, CAST('' AS varchar(20)) AS PartnerBirthDate, CAST(0 AS money)
AS PartnerSalesTotalForDateRange, CAST(0 AS money) AS PartnerSalesTotal, dbo.fnc604S_GetAnniversary(c.Id) as Anniversary,
Coalesce((Select Top 1 cd.DiscountPercent From tbl605_CustDiscount cd Where cd.CustomerId = c.Id),0) as DiscountPercent,
dl.GMTTimeStamp as LastEdited
FROM dbo.tbl600_Customer AS c INNER JOIN
dbo.tbl103_Sites AS sit ON c.SiteId = sit.Id LEFT OUTER JOIN
dbo.tbl601_CustAddress AS cad ON cad.CustomerId = c.Id AND cad.[Default] = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpp ON cpp.CustomerId = c.Id AND cpp.Device = 1 AND cpp.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpf ON cpf.CustomerId = c.Id AND cpf.Device = 3 AND cpf.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpm ON cpm.CustomerId = c.Id AND cpm.Device = 2 AND cpm.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpe ON cpe.CustomerId = c.Id AND cpe.Device = 4 AND cpe.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl405_Employees AS emp ON dbo.fnc600S_GetPrimarySalespersonId(c.Id) = emp.Id OUTER APPLY
(SELECT top 1 GMTTimestamp from dbo.tbl121_DataLog dl where dl.PrimaryKey = c.Id and dl.DBActionId In (600001, 600002) order by dl.GMTTimeStamp DESC) dl
GO
CREATE VIEW [dbo].[viwUser_Customers_Custom]
AS
SELECT c.Id, c.Type, c.CustomerNo, sit.Code AS PrimarySiteCode, sit.Name AS PrimarySiteName, emp.Code AS PrimarySalespersonCode,
emp.Name AS PrimarySalespersonName, c.Title, c.FirstName, c.MiddleName, c.LastName, c.NickName, c.Greeting, c.PreviousName,
dbo.fncCustContactMethodText(c.PreferredContactMethod) AS PreferredContactMethod, cad.Address1, cad.Address2, cad.Address3, cad.City, cad.State,
cad.PostCode, cad.Country, cpp.CountryPrefix AS PhoneCountryPrefix, cpp.AreaCode AS PhoneAreaCode, cpp.Number AS PhoneNumber,
cpp.Extension AS PhoneExtension, dbo.fncCustFormattedPhoneNo(cpp.CountryPrefix, cpp.AreaCode, cpp.Number, cpp.Extension)
AS PhoneNumberFormatted, cpf.CountryPrefix AS FaxCountryPrefix, cpf.AreaCode AS FaxAreaCode, cpf.Number AS FaxNumber,
cpf.Extension AS FaxExtension, dbo.fncCustFormattedPhoneNo(cpf.CountryPrefix, cpf.AreaCode, cpf.Number, cpf.Extension) AS FaxNumberFormatted,
cpm.CountryPrefix AS MobileCountryPrefix, cpm.AreaCode AS MobileAreaCode, cpm.Number AS MobileNumber, cpm.Extension AS MobileExtension,
dbo.fncCustFormattedPhoneNo(cpm.CountryPrefix, cpm.AreaCode, cpm.Number, cpm.Extension) AS MobileNumberFormatted, cpe.EmailAddress, c.Sex,
c.UDFList1, c.UDFList2, c.UDFList3, c.UDFList4, c.UDFList5, c.UDFList6, c.UDFList7, c.UDFList8, c.UDFList9, c.UDFList10, c.UDFList11, c.UDFList12,
c.FingerSize1 AS LeftLittleFingerSize, c.FingerSize2 AS LeftRingFingerSize, c.FingerSize3 AS LeftMiddleFingerSize,
c.FingerSize4 AS LeftIndexFingerSize, c.FingerSize5 AS LeftThumbSize, c.FingerSize6 AS RightThumbSize, c.FingerSize7 AS RightIndexFingerSize,
c.FingerSize8 AS RightMiddleFingerSize, c.FingerSize9 AS RightRingFingerSize, c.FingerSize10 AS RightLittleFingerSize, c.LeftWristSize,
c.RightWristSize, c.NeckSize, c.SocSecNumber, c.POSComments, c.SecureComments, c.Status, c.Active, c.Day, c.Month, c.Year, dbo.fncGetDOB(c.Day,
c.Month, c.Year) AS BirthDate, dbo.fncGetAge(c.Day, c.Month, c.Year, c.Age, c.AgeReferenceDate, GETDATE()) AS Age, CAST('' AS varchar(1000))
AS MailingName, CAST('' AS varchar(1000)) AS GreetingName, CAST(0 AS money) AS CustomerSalesTotalForDateRange, CAST(0 AS money)
AS CustomerSalesTotal, CAST('' AS varchar(50)) AS PartnerCustomerNo, CAST('' AS varchar(20)) AS PartnerBirthDate, CAST(0 AS money)
AS PartnerSalesTotalForDateRange, CAST(0 AS money) AS PartnerSalesTotal, dbo.fnc604S_GetAnniversary(c.Id) as Anniversary,
Coalesce((Select Top 1 cd.DiscountPercent From tbl605_CustDiscount cd Where cd.CustomerId = c.Id),0) as DiscountPercent, (select dbo.fncUser_LastCustomerEditDate(c.CustomerNo)) as LastEdited
FROM dbo.tbl600_Customer AS c INNER JOIN
dbo.tbl103_Sites AS sit ON c.SiteId = sit.Id LEFT OUTER JOIN
dbo.tbl601_CustAddress AS cad ON cad.CustomerId = c.Id AND cad.[Default] = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpp ON cpp.CustomerId = c.Id AND cpp.Device = 1 AND cpp.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpf ON cpf.CustomerId = c.Id AND cpf.Device = 3 AND cpf.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpm ON cpm.CustomerId = c.Id AND cpm.Device = 2 AND cpm.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpe ON cpe.CustomerId = c.Id AND cpe.Device = 4 AND cpe.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl405_Employees AS emp ON dbo.fnc600S_GetPrimarySalespersonId(c.Id) = emp.Id
GO
Time lags of 1-2 minutes querying the SQL view.
I found an easier way to accomplish this. Will just add a SQL trigger to insert a timestamped row into a supplementary table. This table will have the proper construction to make for quicker lookups.

SQL Join with 2 conditions same column but different data names

I need to join 2 tables using 2 columns as identifiers,
Reference and UAP
TABLE 1
Reference
UAP
Week 1
Week 2
Table 2
Reference
UAP
Stock
Here is the problem with data on both tables in UAP column
Table 1 Table 2
UAP1 M1
UAP2 M2
UAP3 M3
UAP4 M4
UAP5 M5
UAP6 M6
UAPP PROTOS
EXT EXTR
the UAPS are the same but name is just different
I have no control over the data i'm getting, it's a IBM DB2 remote server
I tried a local table to join but i want to avoid that 'cause of the performance impact (30+ seconds)
So far my query is this
SELECT
*
FROM OPENQUERY(MACPAC,
'SELECT
P.Referencia,
P.UAP,
P.W01,
P.W02,
S.Stock
FROM AUTO.D805DATPOR.Production AS P
INNER JOIN AUTO.D805DATPOR.Stock S
ON S.Reference = S.Reference
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference')
well of course the ideal would be
SELECT
*
FROM OPENQUERY(MACPAC,
'SELECT
P.Referencia,
P.UAP,
P.W01,
P.W02,
S.Stock
FROM AUTO.D805DATPOR.Production AS P
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND P.UAP = S.UAP
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference')
but it does not work cause different names... Is there a way to make this happen without a local join table that will slow my query by several seconds?
Here is the output of these queries individually
This is the production table
This is the stock table
the output should show me the Stock on the production table by Reference and UAP
EDIT
Sorry for confusion the remote server is IBM DB2. This was an error of my coworker that said it was coming from oracle--
Cheers for correct answer from #Sergey Menshov.
SELECT
Reference,
UAP,
W01,
W02
FROM OPENQUERY(MACPAC,
'SELECT
P.Reference,
P.UAP,
P.W01,
P.W02
FROM AUTO.D805DATPOR.Production AS P
LEFT JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND
S.UAP =
CASE P.UAP
WHEN ''UAP1'' THEN ''M1''
WHEN ''UAP2'' THEN ''M2''
WHEN ''UAP3'' THEN ''M3''
WHEN ''UAP4'' THEN ''M4''
WHEN ''UAP5'' THEN ''M5''
WHEN ''UAP6'' THEN ''M6''
WHEN ''UAPP'' THEN ''PROTOS''
WHEN ''EXT'' THEN ''EXTR''
END
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference DESC')
another method which gives error in UAP1 not a column in table L that might work using dual table for DB2
SELECT
Reference,
UAP,
W01,
W02
FROM OPENQUERY(MACPAC,
'SELECT
P.Reference,
P.UAP,
P.W01,
P.W02
FROM AUTO.D805DATPOR.Production AS P
JOIN
(
SELECT ''UAP1'' AS UAP1, ''M1'' AS UAP2 FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP2'',''M2'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP3'',''M3'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP4'',''M4'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP5'',''M5'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP6'',''M6'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAPP'',''PROTOS'' FROM sysibm.sysdummy1
UNION ALL SELECT ''EXT'',''EXTR'' FROM sysibm.sysdummy1
) L
ON P.UAP = L.UAP1
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND S.UAP = L.UAP2
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference DESC')
Try to use a link-subquery:
FROM AUTO.D805DATPOR.Production AS P
JOIN
(
SELECT ''UAP1'' AS UAP1,''M1'' AS UAP2 FROM DUAL
UNION ALL SELECT ''UAP2'',''M2'' FROM DUAL
UNION ALL SELECT ''UAP3'',''M3'' FROM DUAL
UNION ALL SELECT ''UAP4'',''M4'' FROM DUAL
UNION ALL SELECT ''UAP5'',''M5'' FROM DUAL
UNION ALL SELECT ''UAP6'',''M6'' FROM DUAL
UNION ALL SELECT ''UAPP'',''PROTOS'' FROM DUAL
UNION ALL SELECT ''EXT'',''EXTR'' FROM DUAL
) L
ON P.UAP=L.UAP1 -- !!!
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND S.UAP=L.UAP2 -- !!!
Or you can create a link-table in the Oracle and then use it in your query.
I think it'll be better because you can use it in other queries and insert there a new combinations.
Pseudo code:
CREATE TABLE UAP_LINK(
UAP1 VARCHAR2(20) NOT NULL,
UAP2 VARCHAR2(20) NOT NULL,
PRIMARY KEY(UAP1),
UNIQUE(UAP2)
)
INSERT UAP_LINK VALUES
UAP1, M1
UAP2, M2
UAP3, M3
UAP4, M4
UAP5, M5
UAP6, M6
UAPP, PROTOS
EXT , EXTR
One more variant with CASE:
FROM AUTO.D805DATPOR.Production AS P
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference
AND S.UAP=
CASE P.UAP
WHEN ''UAP1'' THEN ''M1''
WHEN ''UAP2'' THEN ''M2''
WHEN ''UAP3'' THEN ''M3''
WHEN ''UAP4'' THEN ''M4''
WHEN ''UAP5'' THEN ''M5''
WHEN ''UAP6'' THEN ''M6''
WHEN ''UAPP'' THEN ''PROTOS''
WHEN ''EXT'' THEN ''EXTR''
END

T-SQL join query using distinct values from second table

I know this question might sound like a duplicate, but I've been through every question I could find; though it's still possible it might be a duplicate of a question I might have missed.
I have what at surface value appears to be a trivial requirement but no matter how I script it out there's always some caveat that's just not working. I've tried GROUP, DISTINCT, JOIN, aggregate functions, etc.
Scenario:
PRIMARYTABLE contains a set of campaigns and SECONDARYTABLE contains the dates on which campaigns were run. There can be multiple runs per campaign and I've included a SUBKEY for each run.
Requirement:
I need to be able to get the most recently run campaigns into a list so the user can more easily select from the campaigns that get run the most frequent.
PRIMARYTABLE
KEYCOLUMN INFOCOLUMN
100000 Test 1
100001 Test Campaign
100002 Test Image 2
100003 Test Img
100004 Image Test
100005 Test
100006 Test Image 3
100007 Test Image 4
100008 Test Image 5
100009 Image Comparison Test 2
100010 Testing
100011 Test Fields
100012 Test 5
100013 test
SECONDARYTABLE
KEYCOLUMN SUBKEY DATECOLUMN
100000 100000 2017-06-02 04:09:57.593
100001 100001 2017-06-19 12:09:54.093
100001 100002 2017-06-27 10:51:14.140
100004 100003 2017-06-27 12:33:47.747
100006 100004 2017-06-28 10:29:53.387
100007 100005 2017-06-28 10:36:23.710
100008 100006 2017-06-29 22:31:03.790
100009 100007 2017-06-29 23:07:52.870
100009 100010 2017-10-04 16:05:40.583
100009 100011 2017-10-04 16:09:55.470
100011 100008 2017-09-08 14:02:28.017
100012 100009 2017-09-11 16:17:23.870
100013 100012 2017-11-07 16:55:55.403
100013 100013 2017-11-08 15:37:16.430
Below is somewhat of an idea of more or less what I'm after.
SELECT DISTINCT( a.[INFOCOLUMN] )
FROM [PRIMARYTABLE] a
INNER JOIN [SECONDARYTABLE] b ON ( a.[KEYCOLUMN] = b.[KEYCOLUMN] )
ORDER BY a.[DATECOLUMN]
Here's hoping for a Homer Simpson "Doh!" moment once I see how it's supposed to be done.
Much appreciated.
the most recently run campaigns >> use row_number() over(.. order by ... DESC)
that get run the most frequent >> use count(*) over(partition by ..)
Using window functions row_number() over() and count() over() enables selection by row of data that is "most recent" and ordering by "most frequent". Note that the DESCending order of dates brings about "recent" = 1.
select
p.*, s.*
from PRIMARYTABLE p
inner join (
select KEYCOLUMN, SUBKEY, DATECOLUMN
, row_number() over(partition by KEYCOLUMN order by DATECOLUMN DESC) recent
, count(*) over(partition by KEYCOLUMN) frequency
from SECONDARYTABLE
) s on p.KEYCOLUMN = s.KEYCOLUMN and s.recent = 1
order by s.frequency DESC, p.INFOCOLUMN
You can try this:
DECLARE #PRIMARYTABLE TABLE
(
[KEYCOLUMN] INT
,[INFOCOLUMN] VARCHAR(24)
);
DECLARE #SECONDARYTABLE TABLE
(
[KEYCOLUMN] INT
,[SUBKEY] INT
,[DATECOLUMN] DATETIME2
);
INSERT INTO #PRIMARYTABLE ([KEYCOLUMN], [INFOCOLUMN])
VALUES (100000, 'Test 1')
,(100001, 'Test Campaign')
,(100002, 'Test Image 2')
,(100003, 'Test Img')
,(100004, 'Image Test')
,(100005, 'Test')
,(100006, 'Test Image 3')
,(100007, 'Test Image 4')
,(100008, 'Test Image 5')
,(100009, 'Image Comparison Test 2')
,(100010, 'Testing')
,(100011, 'Test Fields')
,(100012, 'Test 5')
,(100013, 'test');
INSERT INTO #SECONDARYTABLE ([KEYCOLUMN], [SUBKEY], [DATECOLUMN])
VALUES (100000, 100000, '2017-06-02 04:09:57.593')
,(100001, 100001, '2017-06-19 12:09:54.093')
,(100001, 100002, '2017-06-27 10:51:14.140')
,(100004, 100003, '2017-06-27 12:33:47.747')
,(100006, 100004, '2017-06-28 10:29:53.387')
,(100007, 100005, '2017-06-28 10:36:23.710')
,(100008, 100006, '2017-06-29 22:31:03.790')
,(100009, 100007, '2017-06-29 23:07:52.870')
,(100009, 100010, '2017-10-04 16:05:40.583')
,(100009, 100011, '2017-10-04 16:09:55.470')
,(100011, 100008, '2017-09-08 14:02:28.017')
,(100012, 100009, '2017-09-11 16:17:23.870')
,(100013, 100012, '2017-11-07 16:55:55.403')
,(100013, 100013, '2017-11-08 15:37:16.430');
SELECT a.[INFOCOLUMN]
,b.[DATECOLUMN]
FROM #PRIMARYTABLE A
CROSS APPLY
(
SELECT TOP 1 [DATECOLUMN]
FROM #SECONDARYTABLE B
WHERE A.[KEYCOLUMN] = B.[KEYCOLUMN]
ORDER BY [DATECOLUMN] DESC
) b;
It will give you the last execution of each campaign. You can filter then by date or ORDER BY and get TOP N from the final query.
Or you can use ROW_NUMBER:
WITH DataSource AS
(
SELECT A.[INFOCOLUMN]
,B.[DATECOLUMN]
,ROW_NUMBER() OVER (PARTITION BY A.[KEYCOLUMN] ORDER BY B.[KEYCOLUMN]) AS [RowID]
FROM #PRIMARYTABLE A
INNER JOIN #SECONDARYTABLE B
ON A.[KEYCOLUMN] = B.[KEYCOLUMN]
)
SELECT [INFOCOLUMN]
,[DATECOLUMN]
FROM DataSource
WHERE [RowID] = 1;
try this, it will return the list of campaigns in most frequent order of use. Note campaigns never run wont appear in your list. in this case you will to do a left join
SELECT a.[INFOCOLUMN]
FROM [PRIMARYTABLE] a
/* left */ JOIN [SECONDARYTABLE] b ON a.[KEYCOLUMN] = b.[KEYCOLUMN]
group BY a.[infocolumn]
order by max(datecolumn) desc
here is a stub i did to test it
select 10000 id,'Campain A' cname into #a1 union all
select 10002,'Campain B' union all
select 10004,'Campain C' union all
select 10009,'Campain E'
select 10000 id,'20170101' thedate into #a2 union all
select 10000,'20170102' union all
select 10009,'20170103' union all
select 10002,'20170104' union all
select 10004,'20170105' union all
select 10000,'20170201' union all
select 10000,'20170302' union all
select 10009,'20170403' union all
select 10002,'20170104' union all
select 10004,'20170205' union all
select 10000,'20170101' union all
select 10004,'20170302' union all
select 10000,'20170103' union all
select 10002,'20170404' union all
select 10002,'20170105'
select #a1.cname
from #a1 join #a2 on #a1.id = #a2.id
group by #a1.cname
order by max(thedate) desc

Sql server XML methods are not allowed in a GROUP BY clause

i just issue a group by where i specify xml data then i got error XML methods are not allowed in a GROUP BY clause.
here is my sql
SELECT HourSheetID,(MAX(RowID)+1) as "RowID",
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') as UpdatedBy,
XMLData.value('(Log/Options)[1]','varchar(max)') as Options,
logdate
FROM dbo.EditedHourSheetLog
GROUP BY HourSheetID,
XMLData.value('(Log/EntryDate)[1]','datetime'),
XMLData.value('(Log/SpecialistID)[1]','int'),
XMLData.value('(Log/HoursData)[1]','decimal(18,2)'),
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)'),
XMLData.value('(Log/Options)[1]','varchar(max)'),
logdate
if i can not specify xml data in group by cluase then what other option is available....please guide. thanks
This way i achieve my task
ALTER PROC sp_HourSheetLog
(
#StartDate VARCHAR(8),
#EndDate VARCHAR(8)
)
AS
SELECT B.ID
,A.RowID
,B.EntryDate
,B.Name
,B.HoursData
,B.UpdatedBy
,Options=(CASE B.Options
WHEN 'rdLeave' THEN 'Leave'
WHEN 'rdsick' THEN 'Sick'
WHEN 'rdSalvage' THEN 'Salvage'
WHEN 'rdCSRDuty' THEN 'CSR Duty'
WHEN 'rdShippingSales' THEN 'Shipping and Sales'
WHEN 'rdEOL' THEN 'EOL'
WHEN 'rdTraining' THEN 'Training'
WHEN 'rdOther' THEN 'Other'
END)
,B.ModDate
FROM (
(
SELECT HourSheetID,(MAX(RowID)+1) as "RowID"
FROM EditedHourSheetLog l,EditedHourSheet h
GROUP BY HourSheetID
) A
JOIN
(
SELECT h.ID
,s.Name
,h.EntryDate
,h.HoursData
,h.Options
,h.UpdatedBy
,h.ModDate from EditedHourSheet h
LEFT JOIN Specialists s
ON h.SpecialistID=s.SpecialistID
) B
ON A.HourSheetID=B.ID
)
WHERE Convert(Varchar,ModDate,112)>=#StartDate AND
Convert(Varchar,ModDate,112)<=#EndDate
UNION
(
Select HourSheetID as ID,RowID,
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
--XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
s.Name,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
CAST(XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') AS VARCHAR(MAX)) UpdatedBy,
Options=(CASE XMLData.value('(Log/Options)[1]','varchar(max)')
WHEN 'rdLeave' THEN 'Leave'
WHEN 'rdsick' THEN 'Sick'
WHEN 'rdSalvage' THEN 'Salvage'
WHEN 'rdCSRDuty' THEN 'CSR Duty'
WHEN 'rdShippingSales' THEN 'Shipping and Sales'
WHEN 'rdEOL' THEN 'EOL'
WHEN 'rdTraining' THEN 'Training'
WHEN 'rdOther' THEN 'Other'
END),
LogDate as ModDate
FROM EditedHourSheetLog h
LEFT JOIN Specialists s
ON h.XMLData.value('(Log/SpecialistID)[1]','int')=s.SpecialistID
WHERE Convert(Varchar,LogDate,112)>=#StartDate AND
Convert(Varchar,LogDate,112)<=#EndDate
)
ORDER BY ID,RowID DESC
--sp_HourSheetLog '20140101','20140326'
You can use a derived table and do the group by in the main query.
SELECT T.HourSheetID,
MAX(T.RowID)+1 as RowID,
T.EntryDate,
T.SpecialistID,
T.HoursData,
T.UpdatedBy,
T.Options,
T.logdate
FROM (
SELECT HourSheetID,
RowID,
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') as UpdatedBy,
XMLData.value('(Log/Options)[1]','varchar(max)') as Options,
logdate
FROM dbo.EditedHourSheetLog
) AS T
GROUP BY T.HourSheetID,
T.EntryDate,
T.SpecialistID,
T.HoursData,
T.UpdatedBy,
T.Options,
T.logdate

T-SQL GROUP BY ISSUE WITH CASE STATEMENT

I have a query with a CASE statement and I need to do a GROUP BY on the alias. I understand that cannot be done so I tried to use a subquery, but it is not working.
Here is the query that I was working on:
SELECT
a.Vendor,
a.Month_Sold
--SUM(sd.SBQSHP) AS Sales_Qty,
--SUM(sd.SBEPRC) AS Sales_Dlr
FROM
(SELECT
sd.IFPRVN AS Vendor,
vn.ACNAME AS Vendor_Name,
CASE
WHEN sd.SBINDT BETWEEN '2012-07-30' AND '2012-08-26' THEN 'August 2012'
WHEN sd.SBINDT BETWEEN '2012-08-27' AND '2012-09-30' THEN 'September 2012'
WHEN sd.SBINDT BETWEEN '2012-10-01' AND '2012-10-28' THEN 'October 2012'
WHEN sd.SBINDT BETWEEN '2012-10-29' AND '2012-11-25' THEN 'November 2012'
WHEN sd.SBINDT BETWEEN '2012-11-26' AND '2012-12-31' THEN 'December 2012'
WHEN sd.SBINDT BETWEEN '2013-01-01' AND '2013-01-27' THEN 'January 2013'
WHEN sd.SBINDT BETWEEN '2013-01-28' AND '2013-02-24' THEN 'Febuary 2013'
WHEN sd.SBINDT BETWEEN '2013-02-25' AND '2013-03-31' THEN 'March 2013'
END AS Month_Sold
FROM
dbo.SalesData sd
INNER JOIN dbo.S2K_VEND vn ON vn.ACVEND = sd.IFPRVN
WHERE
sd.SBINDT > '2012-07-29'
AND
sd.SBCLS IN ('1500')
AND
sd.SBDIV NOT IN ('4000')
)a
GROUP BY
a.Vendor,
a.Month_Sold
ORDER BY
a.Vendor,
a.Month_Sold
The two columns that are commented out need to be included somehow. Any suggestions?
Really, putting pretty labels on your date output should be a job for the presentation tier. FORMAT() in C# etc. is pretty powerful. Barring that, don't convert to pretty string labels until the last possible point, which will require one more layer:
SELECT
Vendor,
DATENAME(MONTH, Month_Sold) + ' ' + RTRIM(YEAR(Month_Sold)),
Sales_Qty,
Sales_Dlr
FROM
(
SELECT
Vendor,
Month_Sold,
SUM(SBQSHP) AS Sales_Qty,
SUM(SBEPRC) AS Sales_Dlr
FROM
(
SELECT
sd.IFPRVN AS Vendor,
vn.ACNAME AS Vendor_Name, -- why is this here?
CASE
WHEN sd.SBINDT BETWEEN '2012-07-30' AND '2012-08-26' THEN '2012-08-01'
WHEN sd.SBINDT BETWEEN '2012-08-27' AND '2012-09-30' THEN '2012-09-01'
...
WHEN sd.SBINDT BETWEEN '2013-01-28' AND '2013-02-24' THEN '2013-02-01'
WHEN sd.SBINDT BETWEEN '2013-02-25' AND '2013-03-31' THEN '2013-03-01'
END AS Month_Sold
FROM dbo.SalesData sd
INNER JOIN dbo.S2K_VEND vn
ON vn.ACVEND = sd.IFPRVN
WHERE sd.SBINDT > '2012-07-29'
AND sd.SBCLS IN ('1500')
AND sd.SBDIV NOT IN ('4000')
) AS a
GROUP BY Vendor, Month_Sold
) AS b
ORDER BY
Vendor,
Month_Sold;
Simply select the values you need to aggregate in your subquery with alias "a"
Add to subquery "a" select statement:
SELECT
sd.IFPRVN AS Vendor,
vn.ACNAME AS Vendor_Name,
sd.SBQSHP,
sd.SBEPRC
CASE
...
Uncomment SUM statements at top level select statement but change alias from "sd" to "a"
SUM(a.SBQSHP) AS Sales_Qty,
SUM(a.SBEPRC) AS Sales_Dlr

Resources