ORDER BY when using value gotten from sql function - sql-server

I have this SQL for creating the procedure:
create procedure [dbo].[spGetProduct](#col_sort varchar(100), #dir_sort varchar(4), #filters nvarchar(max)) as
begin
declare #temp table (
row_num int,
product_id int,
product_name nvarchar(255),
produnit_name nvarchar(50)
)
insert into #temp
EXEC('select * from (select (ROW_NUMBER() OVER (ORDER BY '+#col_sort+' '+#dir_sort+')) row_num, product_id, product_name, dbo.fnGetUnitName(ing_produnit) produnit_name
from dbo.Products
where '+#filters+') as tmp)
select * from #temp
end
Info:
dir_sort can be asc or desc and col_sort is a string that contains one of the column names.
Filters in this case is irrelevant.
When col_sort has the value product_id or product_name it is working fine, but when I call it with produnit_name it throws error.
How can I order the data by that column in this case?
Edit:
The error is:
Invalid column name 'produnit_name'.

You can't reference an alias in the OVER() clause at the same scope, since the alias is defined after the OVER() clause is evaluated. This is the same reason you can't GROUP BY alias or say WHERE alias = 1 - the alias hasn't been defined yet in those cases, either.
If you can't use a join instead of the function to derive the unit name, then you will have to nest again, e.g.
insert into #temp
EXEC('select * from (select (ROW_NUMBER() OVER
(ORDER BY '+#col_sort+' '+#dir_sort+')) row_num, * FROM
(SELECT product_id, product_name,
dbo.fnGetUnitName(ing_produnit) produnit_name
from dbo.Products
where '+#filters+') AS x) as tmp');

That is because produnit_name is a derived column. While you can use a derived column in an ORDER BY clause, you cannot use it with ROW_NUMBER OVER.

Related

How to create another table or Temp table with the Pivot query results

I have this table
CREATE TABLE COMPUTERS
(
CUSTOMER_ID INT,
COMPUTER_NAME VARCHAR(50),
COMPUTER_OS VARCHAR(50)
);
INSERT INTO COMPUTERS
VALUES (15001, 'DESKTOP-JKVB','Windows 7'),
(15001, 'DESKTOP-SKVB','Windows 2012R2'),
(15002, 'PC-JKVB45','Windows VISTA'),
(15002, 'JOHN-PC','Windows 10'),
(15002, 'SERVER-DC','Windows 7'),
(15002, 'DATA-PC','Windows 2016'),
(15002, 'PC-BACKOFFICE','Windows 2008R2'),
(15003, 'DESKTOP-XPBACK','Windows 7'),
(15003, 'PC-HDFU','Windows 2012R2'),
(15003, 'DESKTOP-NO2','Windows 10'),
(15004, 'SERVER-DHCP','Windows 7'),
(15004, 'DESKTOP-NO1','Windows 2012R2');
With the help of Stack overflow , i have written a query to pivot the above data.
My question is whether we can create a temp table or normal table with result of the pivot data.
PIVOT QUERY
;WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Customer_ID ORDER BY Customer_ID) AS Number
FROM computers
),
cte2 AS
(
SELECT DISTINCT
c.Customer_ID,
c.Computer_Name,
'Computer_Name_' + CAST(Number AS VARCHAR(100)) AS Computer
FROM
cte AS c
),
cte_dist2 AS
(
SELECT DISTINCT Customer_ID
FROM computers
),
cte3 AS
(
SELECT
c.Customer_ID, c.Computer_OS,
'Computer_OS_' + CAST(Number AS VARCHAR(100)) AS OS
FROM
cte AS c
)
SELECT DISTINCT
cd2.Customer_ID,
MAX(IIF(c2.Computer='Computer_Name_1',c2.Computer_Name,NULL)) as Computer_Name_1,
MAX(IIF(c3.OS='Computer_OS_1',c3.Computer_OS,NULL)) as Computer_OS_1,
MAX(IIF(c2.Computer='Computer_Name_2',c2.Computer_Name,NULL)) as Computer_Name_2,
MAX(IIF(c3.OS='Computer_OS_2',c3.Computer_OS,NULL)) as Computer_OS_2,
MAX(IIF(c2.Computer='Computer_Name_3',c2.Computer_Name,NULL)) as Computer_Name_3,
MAX(IIF(c3.OS='Computer_OS_3',c3.Computer_OS,NULL)) as Computer_OS_3,
MAX(IIF(c2.Computer='Computer_Name_4',c2.Computer_Name,NULL)) as Computer_Name_4,
MAX(IIF(c3.OS='Computer_OS_4',c3.Computer_OS,NULL)) as Computer_OS_4,
MAX(IIF(c2.Computer='Computer_Name_5',c2.Computer_Name,NULL)) as Computer_Name_5,
MAX(IIF(c3.OS='Computer_OS_5',c3.Computer_OS,NULL)) as Computer_OS_5
FROM
cte_dist2 AS cd2
INNER JOIN
cte2 AS c2 ON cd2.Customer_ID = c2.Customer_ID
INNER JOIN
cte3 AS c3 ON cd2.Customer_ID = c3.Customer_ID
GROUP BY
cd2.Customer_ID
Yes you can use temp tables below show two methods that you can use for creating temp tables
select * into #temp from (--select query of the final cte function
or query) and temp table will be automatically create for you.
If you want to create your own temp table create temp table like below.
Eg
create table #Temp
(
EventID int,
EventTitle Varchar(50),
EventStartDate DateTime,
EventEndDate DatetIme,
EventEnumDays int,
EventStartTime Datetime,
EventEndTime DateTime,
EventRecurring Bit,
EventType int
)
and use Insert Into #Temp --select query of the final cte function
or query will also work for you.

Filling the ID column of a table NOT using a cursor

Tables have been created and used without and ID column, but ID column is now needed. (classic)
I heard everything could be done without cursors. I just need every row to contain a different int value so I was looking for some kind of row number function :
How do I use ROW_NUMBER()?
I can't tell exactly how to use it even with these exemples.
UPDATE [TableA]
SET [id] = (select ROW_NUMBER() over (order by id) from [TableA])
Subquery returned more than 1 value.
So... yes of course it return more than one value. Then how to mix both update and row number to get that column filled ?
PS. I don't need a precise order, just unique values. I also wonder if ROW_NUMBER() is appropriate in this situation...
You can use a CTE for the update
Example
Declare #TableA table (ID int,SomeCol varchar(50))
Insert Into #TableA values
(null,'Dog')
,(null,'Cat')
,(null,'Monkey')
;with cte as (
Select *
,RN = Row_Number() over(Order by (Select null))
From #TableA
)
Update cte set ID=RN
Select * from #TableA
Updated Table
ID SomeCol
1 Dog
2 Cat
3 Monkey
You can use a subquery too as
Declare #TableA table (ID int,SomeCol varchar(50))
Insert Into #TableA values
(null,'Dog')
,(null,'Cat')
,(null,'Monkey');
UPDATE T1
SET T1.ID = T2.RN
FROM #TableA T1 JOIN
(
SELECT ROW_NUMBER()OVER(ORDER BY (SELECT 1)) RN,
*
FROM #TableA
) T2
ON T1.SomeCol = T2.SomeCol;
Select * from #TableA

Inserting into a primary key field in SQL Server

Is there a way to increment an ID field that has a primary key in an INSERT INTO SELECT statement?
What I would want to do is take the last ID of the table and insert an incremented ID with each new record produced by the INSERT INTO SELECT statement?
You can do it like this:
DECLARE #lastId int = 0
SELECT #lastId = MAX(Id) From YourTable
INSERT INTO YourTable (Id, Data)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT 0))) + #lastId, at.Data
FROM AnotherTable at
Be sure to add it inside a Transaction scope.
SqlFiddle: http://www.sqlfiddle.com/#!3/d23642/5
Anyway I strongly suggest you to use an IDENTITY column to avoid collisions.
Maybe get the max id and then increse in one on each Insert
INSERT MAX(ID)+1
I think something like this is what you are looking for. Let's assume the PK is an INT for demo purposes.
--Get the last/greatest PK value in first table.
DECLARE #LastPKValue INT
SELECT #LastPKValue = MAX(PKCol)
FROM [schema].[YourTable]
INSERT INTO [schema].[YourTable] (PKCol, ColA, ColB, ColC)
SELECT
ROW_NUMBER() OVER( ORDER BY sot.[SomeColumnName]) + #LastPKValue,
OtherColumnA,
OtherColumnB,
OtherColumnC
FROM [schema].[SomeOtherTable] sot

Removing duplicate rows while also updating relations

My data is set up as follows:
CREATE TABLE TableA
(
id int IDENTITY,
name varchar(256),
description varchar(256)
)
CREATE TABLE TableB
(
id int IDENTITY,
name varchar(256),
description varchar(256)
) --unique constraint on name, description
CREATE TABLE TableA_TableB
(
idA int,
idB int
) --composite key referencing TableA and TableB
The situation is that I have many duplicate records in TableB that violate the unique constraint, and those duplicate records are referenced in TableA_TableB. So I'm trying to remove those records, which is simple enough (using the following CTE), but what would be the best way to update the records in TableA_TableB to reflect this change, i.e, have the TableA_TableB records reference the same ID in TableB as opposed to different IDs for each of the duplicates?
;WITH cte
AS (SELECT ROW_NUMBER() OVER (PARTITION BY [Name], [Description]
ORDER BY ( SELECT 0)) RN
FROM TableB)
DELETE FROM cte
WHERE RN = 1
Note: changed b.RowNum=1 to b.RowNum>1
First, you should try with ROLLBACK and then, if it's OK, uncomment COMMIT (this script wasn't tested):
DECLARE #UpdatedRows TABLE(ID INT PRIMARY KEY);
BEGIN TRANSACTION;
;WITH Base
AS(
SELECT ROW_NUMBER() OVER (PARTITION BY [Name], [Description] ORDER BY ( SELECT 0)) RowNum,
MIN(id) OVER(PARTITION BY [Name], [Description]) AS NewID,
ID -- Old ID
FROM TableB
),TableB_RowsForUpdate
AS(
SELECT *
FROM Base b
WHERE b.RowNum>1
)
UPDATE target
SET IDB=b.NewID
OUTPUT deleted.IDB INTO #UpdatedRows
FROM TableA_TableB target
INNER JOIN TableB_RowsForUpdate b ON target.IDB=b.ID;
DELETE b
FROM TableB b INNER JOIN #UpdatedRows upd ON b.ID=upd.ID;
ROLLBACK;
-- COMMIT;

How to sort date in mssqlserver

I want to get distinct dates from my dbtable named tblFormno2 in an ascending order.For that i've written the following query but its not working properly.
Column date_submit is declared as datetime
select distinct (convert(nvarchar(100),date_submit,103)) as dob from
tblFormno2 order by dob asc
Here the the output is shown as
05/07/2011
06/03/2011
06/07/2011
07/04/2011
08/01/2012
instead of
06/03/2011
07/04/2011
05/07/2011
06/07/2011
08/01/2012
How to solve this problem ???
How about
select convert(nvarchar(10), date_submit_inner, 103) as date_submit from
(
select distinct date_submit as date_submit_inner from tblFormno2
) as T
order by T.date_submit_inner asc
Your order by is not sorting by date_submit from the table. Is is sorting by the named output column of date_submit. If you specific the table name in the order by it should work. If that doesn't work, then try giving the output a different name than the table column.
select distinct (Convert(nvarchar(100),date_submit,103)) as date_submit
from tblFormno2
order by tblFormno2.date_submit asc
create table #temp
(
DT varchar(20)
)
Insert into #temp(DT)values('13/05/2011')
Insert into #temp(DT)values('03/06/2011')
Insert into #temp(DT)values('07/06/2011')
Insert into #temp(DT)values('04/07/2011')
Insert into #temp(DT)values('01/08/2011')
Select * from #temp
Below are the database records...
select (convert(varchar,Dt,107)) t into #t from #temp
select * from #t
drop table #temp
drop table #t

Resources