Make a single column value from multiple rows column - sql

I am facing a very isolated problem regarding to the dynamic sql query. I have two queries running on a single stored procedure. They are following
First query:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY viwPerformance.LastModifiedOn DESC) AS rowNumber,viwPerformance.* FROM viwPerformance WHERE OrgId=218 AND EmployeeId = 1668 AND IsTerminate = 0 AND TagId LIKE '%' + CAST(2893 AS VARCHAR) + '%' AND Archive='False' AND SmartGoalId IS NOT NULL
) AS E
WHERE rowNumber >= 1 AND
rowNumber < 11
it results all the column values and the SmartGoalId as
4471,2815,4751,4733,4863,4690,4691,4692,4693,4694
And the second query (here I need only SmartgoalId from the above query so I use stuff)
SELECT #strGoalIds = STUFF((SELECT ',' + CAST(SmartGoalId AS VARCHAR)
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY viwPerformance.LastModifiedOn DESC) AS rowNumber,viwPerformance.* FROM viwPerformance WHERE OrgId=218 AND EmployeeId = 1668 AND IsTerminate = 0 AND TagId LIKE '%' + CAST(2893 AS VARCHAR) + '%' AND Archive='False' AND SmartGoalId IS NOT NULL
) AS E
WHERE rowNumber >= 1 AND
rowNumber < 11 FOR XML PATH('')), 1, 1, '')
and it's results the SmartgoalId as
4471,2815,4751,4733,4863,4651,4690,4691,4692,4693
Please note that the last id "4694" is not available from above query as the "4651"is added to it but it's not available from first query and this is correct that "4651" should not be in the second query result.
So my main point is why the second query gives different results as it's the same as the first query.
Note: Am I right that the Stuff function reversing the values and not giving them in correct order.

Because you have some rows with the same value for LastModifiedOn it depends how you want to handle ties.
If you want this query to always return the 10 most "recent" rows but always return the same ones when there are ties you can add another column to your ORDER BY viwPerformance.LastModifiedOn DESC clause that will make the sort unique and unchanging, like:
ORDER BY viwPerformance.LastModifiedOn,viwPerformance.SmartGoalId DESC)

Related

How to get data from 2 rows which has same data in all columns except one in MSSQL

As in my title I want to take data from 2 rows but In my case each 2nd row has one different value compare to the first row.
I want to take all the common data along with the different data as a single row .
Here you can see each row has same values in another row except the 2nd rows last column.
Thanks.
Edits Result :
I suspect you have a some kind of ordering columns that could specify your actual data ordering if so, then you can use row_number() function
select * from (
select *,
row_number() over (partition by <common data cols> order by ? desc) Seq
from table t
) t
where seq = 1;
EDIT : I don't believe your inventort_item_id columns but yes you could use creation_date for ordering purpose
SELECT
EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE,
BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION AS POPULAR_PRODUCTS_IMAGE_PATHS
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY ITEM_CODE ORDER BY creation_date DESC) as Seq
FROM ECOM_PRODUCT_IMAGES EPI
) EPI
INNER JOIN ECOM_POPULAR_PRODUCTS_MAPPING EPPIM ON EPPIM.ITEM_CODE = EPI.ITEM_CODE
INNER JOIN LOM_MST_PRODUCT LMP ON LMP.PROD_CODE = EPI.ITEM_CODE
INNER JOIN LOM_LNK_PROD_COMP LLPC ON LLPC.COLOC_PROD_CODE = LMP.PROD_CODE
WHERE EPI.Seq = 1 AND
EPPIM.ITEM_STATUS = 'ACTIVE';
EDIT 2: In that case you need to use GROUP BY clause with conditional aggregation
SELECT
EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE,
MAX(CASE WHEN EPI.Seq = 2
THEN (BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION)
END) AS POPULAR_PRODUCTS_IMAGE_PATHS,
MAX(CASE WHEN EPI.Seq = 1
THEN (BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION)
END) AS PATH_NEW
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY ITEM_CODE ORDER BY creation_date DESC) as Seq
FROM ECOM_PRODUCT_IMAGES EPI
) EPI
INNER JOIN ECOM_POPULAR_PRODUCTS_MAPPING EPPIM ON EPPIM.ITEM_CODE = EPI.ITEM_CODE
INNER JOIN LOM_MST_PRODUCT LMP ON LMP.PROD_CODE = EPI.ITEM_CODE
INNER JOIN LOM_LNK_PROD_COMP LLPC ON LLPC.COLOC_PROD_CODE = LMP.PROD_CODE
WHERE EPPIM.ITEM_STATUS = 'ACTIVE'
GROUP BY EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE;
here is my approach, also using a window function.
sample data
if object_id('tempdb..#x') is not null drop table #x
CREATE TABLE #x (ITEM_CODE VARCHAR(10), PROD_DESC VARCHAR(20),
COLOR_PROD_PRICE DECIMAL, POPULAR_PRODUCTS_IMAGE_PATHS VARCHAR(200))
INSERT INTO #X(ITEM_CODE,PROD_DESC,COLOR_PROD_PRICE,POPULAR_PRODUCTS_IMAGE_PATHS) VALUES
('P0001', 'Axe Brand', 88.000, 'some_path_to_img1.jpg'),
('P0001', 'Axe Brand', 88.000, 'some_path_to_img2.jpg'),
('P0002', 'Almond Nuts', 499.000, 'some_path_to_img1.jpg'),
('P0002', 'Almond Nuts', 499.000, 'some_path_to_img2.jpg')
query - just change #x to your table and it should work
;WITH my_cte as
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY ITEM_CODE ORDER BY POPULAR_PRODUCTS_IMAGE_PATHS) AS 'track_row'
FROM #x
)
SELECT a.ITEM_CODE, a.PROD_DESC, a.COLOR_PROD_PRICE,
a.POPULAR_PRODUCTS_IMAGE_PATHS + ' ' + b.POPULAR_PRODUCTS_IMAGE_PATHS AS 'POPULAR_PRODUCTS_IMAGE_PATHS'
FROM my_cte AS a
INNER JOIN
my_cte AS b ON a.ITEM_CODE=b.ITEM_CODE
WHERE a.track_row=1 AND b.track_row=2
output
ITEM_CODE PROD_DESC COLOR_PROD_PRICE POPULAR_PRODUCTS_IMAGE_PATHS
P0001 Axe Brand 88 some_path_to_img1.jpg some_path_to_img2.jpg
P0002 Almond Nuts 499 some_path_to_img1.jpg some_path_to_img2.jpg

Alphanumeric sort on nvarchar(50) column

I am trying to write a query that will return data sorted by an alphanumeric column, Code.
Below is my query:
SELECT *
FROM <<TableName>>
CROSS APPLY (SELECT PATINDEX('[A-Z, a-z][0-9]%', [Code]),
CHARINDEX('', [Code]) ) ca(PatPos, SpacePos)
CROSS APPLY (SELECT CONVERT(INTEGER, CASE WHEN ca.PatPos = 1 THEN
SUBSTRING([Code], 2,ISNULL(NULLIF(ca.SpacePos,0)-2, 8000)) ELSE NULL END),
CASE WHEN ca.PatPos = 1 THEN LEFT([Code],
ISNULL(NULLIF(ca.SpacePos,0)-0,1)) ELSE [Code] END) ca2(OrderBy2, OrderBy1)
WHERE [TypeID] = '1'
OUTPUT:
FFS1
FFS2
...
FFS12
FFS1.1
FFS1.2
...
FFS1.1E
FFS1.1R
...
FFS12.1
FFS12.2
FFS.12.1E
FFS12.1R
FFS12.2E
FFS12.2R
DESIRED OUTPUT:
FFS1
FFS1.1
FFS1.1E
FFS1.1R
....
FFS12
FFS12.1
FFS12.1E
FFS12.1R
What am I missing or overlooking?
EDIT:
Let me try to detail the table contents a little better. There are records for FFS1 - FFS12. Those are broken into X subs, i.e., FFS1.1 - FFS1.X to FFS12.1 - FFS12.X. The E and the R was not a typo, each sub record has two codes associated with it: FFS1.1E & FFS1.1R.
Additionally I tried using ORDER BY but it sorted as
FFS1
...
FFS10
FFS2
This will work for any count of parts separated by dots. The sorting is alphanumerical for each part separately.
DECLARE #YourValues TABLE(ID INT IDENTITY, SomeVal VARCHAR(100));
INSERT INTO #YourValues VALUES
('FFS1')
,('FFS2')
,('FFS12')
,('FFS1.1')
,('FFS1.2')
,('FFS1.1E')
,('FFS1.1R')
,('FFS12.1')
,('FFS12.2')
,('FFS.12.1E')
,('FFS12.1R')
,('FFS12.2E')
,('FFS12.2R');
--The query
WITH Splittable AS
(
SELECT ID
,SomeVal
,CAST(N'<x>' + REPLACE(SomeVal,'.','</x><x>') + N'</x>' AS XML) AS Casted
FROM #YourValues
)
,Parted AS
(
SELECT Splittable.*
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS PartNmbr
,A.part.value(N'text()[1]','nvarchar(max)') AS Part
FROM Splittable
CROSS APPLY Splittable.Casted.nodes(N'/x') AS A(part)
)
,AddSortCrit AS
(
SELECT ID
,SomeVal
,(SELECT LEFT(x.Part + REPLICATE(' ',10),10) AS [*]
FROM Parted AS x
WHERE x.ID=Parted.ID
ORDER BY PartNmbr
FOR XML PATH('')
) AS SortColumn
FROM Parted
GROUP BY ID,SomeVal
)
SELECT ID
,SomeVal
FROM AddSortCrit
ORDER BY SortColumn;
The result
ID SomeVal
10 FFS.12.1E
1 FFS1
4 FFS1.1
6 FFS1.1E
7 FFS1.1R
5 FFS1.2
3 FFS12
8 FFS12.1
11 FFS12.1R
9 FFS12.2
12 FFS12.2E
13 FFS12.2R
2 FFS2
Some explanation:
The first CTE will transform your codes to XML, which allows to address each part separately.
The second CTE returns each part toegther with a number.
The third CTE re-concatenates your code, but each part is padded to a length of 10 characters.
The final SELECT uses this new single-string-per-row in the ORDER BY.
Final hint:
This design is bad! You should not store these values in concatenated strings... Store them in separate columns and fiddle them together just for the output/presentation layer. Doing so avoids this rather ugly fiddle...

SQL Query How to ensure that ROW_NUMBER() OVER(PARTITION BY... always has a ROW_NUMBER = '1' in result set

I've created a view that returns a row number for each record. My requirements are that the results must always have a line 1, incremented by 1. This works fine as long as all line items are selected from a given record. However, when only some of the line items from a record are selected, the set of row numbers for the selected line items may or may not have a row number = 1. Below is an example of my code:
SELECT a.PATID,
a.PATID + '_' + a.BATCHID + '_' + a.UNIQUEID AS RECORD_ID,
ROW_NUMBER() OVER(PARTITION_BY b.BATCHID, b.UNIQUIEID, b.LINE_ID) AS LN_NBR,
a.ADMIT_DT,
b.REV,
b.SERVICE_DATE AS DOS
FROM HDR_TBL a
LEFT JOIN LINE_ITEM_TBL b
WHERE b.PD_STATUS = 'P'
Here is an example of the results:
PATID |RECORD_ID |LN_NBR|ADMIT_DT |REV |DOS |
-----|-----------|------|--------|----|--------|
21548|017_U50_011|1 |20170721|0124|20170721|
21548|017_U50_011|2 |20170722|0214|20170722|
21548|017-U50_011|3 |20170723|0124|20170723|
51245|017_U27_003|3 |20170701|0124|20170701|
51245|017_U27_003|4 |20170702|0124|20170702|
As you can see the last 2 records have LN_NBR = 3 and 4; I need to generate the last 2 record with LN_NBR = 1 and 2 instead.
Anyone have an idea how I can force this to happen?
Thanks!
Your PARTITION BY need to match your RECORD_ID
In this case should be
OVER (PARTITION BY a.PATID, a.BATCHID, a.UNIQUEID ORDER BY <something>)
You have the fields you should have in an ORDER BY condition in the PARTITION BY condition. It should be:
SELECT a.PATID,
a.PATID + '_' + a.BATCHID + '_' + a.UNIQUEID AS RECORD_ID,
ROW_NUMBER() OVER(PARTITION_BY a.RECORD_ID ORDER BY b.BATCHID, b.UNIQUIEID, b.LINE_ID) AS LN_NBR,
a.ADMIT_DT,
b.REV,
b.SERVICE_DATE AS DOS
FROM HDR_TBL a
LEFT JOIN LINE_ITEM_TBL b
WHERE b.PD_STATUS = 'P'

How to use ROWNUM with nested queries

SELECT * FROM(
SELECT * FROM(
SELECT PART_NO, SRC_PART_NO, CTNM_ENG, DESCRIPTION, USER_ID, REG_DT, CHG_DT, FLAG,
(select count(*) from ( SELECT PART_NO, SRC_PART_NO, CTNM_ENG, DESCRIPTION, USER_ID, REG_DT, CHG_DT, FLAG
FROM GM_PART_LIST
WHERE PART_NO LIKE '%' || '%' AND SRC_PART_NO LIKE '%' || '%' AND CTNM_ENG LIKE 'BOLT'|| '%'
AND 1 = 1) ) as total_count -- Nested subquery that return total count of record set. plug in same where conditions.
FROM GM_PART_LIST
WHERE PART_NO LIKE '%' || '%' AND SRC_PART_NO LIKE '%' || '%' AND CTNM_ENG LIKE 'BOLT'|| '%'
AND 1 = 1
ORDER BY PART_NO ASC))
WHERE ROWNUM BETWEEN 2 AND 202;
How is it that with the above query if I search between 1 and 200 It pulls records fine but when I switch it to 2 or another integer above 1 it fails to query any records?
is this a syntax issue? thank you in advance for any help anyone can offer.
ROWNUM is assigned when a row is evaluated for the where conditions. The first row from the row source is retrieved and given ROWNUM=1. If one of the were conditions is ROWNUM > 1, this row will not be selected.
Then ROWNUM=1 is reassigned to the next row (which again will fail the where clause) and so on. This is because in the end ROWNUM must run consecutively from 1, it will not be a sequence with gaps. So any condition that doesn't allow ROWNUM to be 1 (example: where mod(ROWNUM, 2) = 0) will produce zero rows, and for exactly the same reason.

sql server using SUBSTRING with LIKE operator returns no results

I created this CTE that returns first and last names from 2 different tables. I would like to use the CTE to identify all of the records that have the same last names and the first name of one column starts with the same first letter of another column.
This is an example of the results of the CTE. I want the SELECT using the CTE to return only the highlighted results:
;WITH CTE AS
(
SELECT AD.FirstName AS AD_FirstName, AD.LastName AS AD_LastName, NotInAD.FirstName As NotInAD_FirstName, NotInAD.LastName As NotInAD_LastName
FROM PagingToolActiveDirectoryUsers AD JOIN
(
SELECT FirstName, LastName
FROM #PagingUsersParseName
EXCEPT
SELECT D.FirstName, D.LastName
FROM PagingToolActiveDirectoryUsers D
WHERE D.FirstName <> D.LastName AND D.LastName <> D.LoginName
AND D.LoginName LIKE '%[0-9]%[0-9]%'
) AS NotInAD ON NotInAD.LastName = AD.LastName
)
SELECT *
FROM CTE
WHERE (AD_LastName = NotInAD_LastName) AND (AD_FirstName LIKE ('''' + SUBSTRING(NotInAD_FirstName, 1, 1) + '%'''))
ORDER BY AD_LastName, AD_FirstName;
The result of this query returns no rows.
What am I doing wrong?
Thanks.
You're enclosing the string to be searched for with single-quotes, but it doesn't appear that the data in AD_FirstName has those single-quotes embedded in it. I suggest you replace the first line of the WHERE clause with
WHERE (AD_LastName = NotInAD_LastName) AND (AD_FirstName LIKE (SUBSTRING(NotInAD_FirstName, 1, 1) + '%'))
Best of luck.