Populate table variable with ordered results - sql

I would like to populate table variable with results from CADEPA table. The only problem is that those results must be ordered.
The error I am receiving is:
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
Query is:
DECLARE #DEPARTMENTS_TBL TABLE
(
DEPA_KEY INT
)
INSERT INTO #DEPARTMENTS_TBL(DEPA_KEY)
SELECT DEPA_KEY
FROM (
SELECT DISTINCT DEPA_KEY
FROM CADEPA
WHERE DEPA_STA = '1'
ORDER BY DEPA_NME
) P

Tables represent unordered sets. To do what you want, you need a key to represent the ordering:
DECLARE #DEPARTMENTS_TBL TABLE (
ID IDENTITY(1, 1) PRIMARY KEY
DEPA_KEY INT
);
INSERT INTO #DEPARTMENTS_TBL (DEPA_KEY)
SELECT DEPA_KEY
FROM CADEPA
WHERE DEPA_STA = '1'
GROUP BY DEPA_KEY
ORDER BY MAX(DEPA_NME);
I also think you should include DEPA_NME in the table, but the id column will keep the ordering.
Be sure you query with order by:
select d.*
from DEPARTMENTS_TBL d
order by id;

Move order by clause at the end after you table alias (P)
INSERT INTO #DEPARTMENTS_TBL(DEPA_KEY)
SELECT DISTINCT DEPA_KEY
FROM (
SELECT DEPA_KEY, DEPA_NME
FROM CADEPA
WHERE DEPA_STA = '1'
) P
ORDER BY DEPA_NME

Related

Pick Max Date from Table

I have a table variable defined thus
DECLARE #DatesTable TABLE
(
Id uniqueidentifier,
FooId uniqueidentifier,
Date date,
Value decimal (26, 10)
)
Id is always unique but FooId is duplicated throughout the table. What I would like to do is to select * from this table for each unique FooId having the max(date). So, if there are 20 rows with 4 unique FooIds then I'd like 4 rows, picking the row for each FooId where the date is the largest.
I've tried using group by but I kept getting errors about various fields not being in the select clause etc.
Use a common table expression with row_number():
;WITH cte AS
(
SELECT Id, FooId, Date, Value,
ROW_NUMBER() OVER(PARTITION BY FooId ORDER BY Date DESC) As rn
FROM #DatesTable
)
SELECT Id, FooId, Date, Value
FROM cte
WHERE rn = 1
Often the most efficient method is a correlated subquery:
select dt.*
from #DatesTable dt
where dt.date = (select max(dt2.date) from #DatesTable dt2 where dt2.fooid = dt.fooid);
However, for this to be efficient, you need an index on (fooid, date). In more recent versions of SQL Server, you can have indexes on table variables. In earlier versions, you can do this using a primary key.

Select from multiple table, order the records with limits and union/join them together

I have the following stored procedure:
CREATE PROCEDURE [dbo].[P24GamesByCategoryDesktopEn]
#Index int
AS
Begin
SELECT GameName, IMG380X380, GameCode, '9' AS ProviderID
FROM BGames
WHERE GameType = 'slots'
UNION ALL
SELECT Name, ImageUrl, GameID , '12' AS ProviderID
FROM EGame
WHERE Type = 'slots'
ORDER BY GameName OFFSET #Index ROWS FETCH NEXT 4 ROWS ONLY
END
I wan to select from two unrelated tables (that have no relationship between them) a number of records. Then I want to join the results of both table into one result set using the 'union' syntax.
However, the query doesnt work, because the order clause relates to the result set after the union has occured. That means that more records are returned from one of the tables.. but I need to return an equal number of results from each select query.
I want to use the order by clause after each select statement, but sql server wont allow such a syntax.
How can I join the tables and their results into one result set.
Note, I dont want to do a select subquery or create many temp tables. Thats because I am going to add a lot more select statements into that stored procedure..and I dont want it to be inefficient or too convulted.
You pretty much just need to wrap up your different queries that you want to order by and "paginate" in CTE's like so:
DECLARE #Index int = 0, #NbrOfRows int = 4
; WITH CTE1 AS (
SELECT GameName, IMG380X380, GameCode, '9' AS ProviderID
FROM BGames
WHERE GameType = 'slots'
ORDER BY GameName
OFFSET #Index ROWS FETCH NEXT #NbrOfRows ROWS ONLY
), CTE2 AS (
SELECT Name, ImageUrl, GameID, '12' AS ProviderID
FROM EGame
WHERE Type = 'slots'
ORDER BY GameName
OFFSET #Index ROWS FETCH NEXT #NbrOfRows ROWS ONLY
)
SELECT * FROM CTE1
UNION ALL
SELECT * FROM CTE2
You just need to add naming to the columns so that they are as you wish them to be at the end of the union.
I think you get around this with row_number().
This is two selects of the same table but it could be different tables.
SELECT [AuctionId]
,[UserId]
,[BiddingPrice]
,[DateTime]
,9 as [source]
,ROW_NUMBER() over (order by [DateTime] asc) as rn
FROM [Test].[dbo].[Bid]
union all
SELECT [AuctionId]
,[UserId]
,[BiddingPrice]
,[DateTime]
,12 as [source]
,ROW_NUMBER() over (order by [DateTime] desc) as rn
FROM [Test].[dbo].[Bid]
ORDER BY rn, source OFFSET 2 ROWS FETCH NEXT 4 ROWS ONLY

Table valued Function - Identity(seed, increment)

I have a Table Valued Function qlikview_verlauf. I want to return a table with id, Date and Path.
Identity(seed, increment)
The ID is an autoincrement value. I want to start this autoincrement (seed) from the max(id)+1 from another table named Testfortschritt.
I have tried the following, but it doesn't work. The Error Message is incorrect Syntax.
Create FUNCTION [dbo].[qlikview_verlauf](#param INT)
RETURNS #qlikview_verlauf table (
ID INT IDENTITY((Select max(id) from Testfortschritt),1)
,[Date] date NOT NULL
,[Path] varchar(600) NOT NULL
)
I would set aside the IDENTITY of your ID column and rather use ROW_NUMBER to generate the ID in your SELECT statement.
For example:
SELECT
(SELECT MAX(id) FROM Testfortschritt) +
ROW_NUMBER OVER(ORDER BY (SELECT 1)) AS ID,
[Date],
[Path]
FROM <YourTable>
Since I don't know how your exact statement looks like, I used ORDER BY (SELECT 1) which lets SQL Server decide in which order records are numbered. If you have a specific order just replace (SELECT 1) with your order columns.
Since the ID should be uniqe I also omitted the PARTITION BY clause which isn't needed in your scenario.
More about ROW_NUMBER can be found here

Select a Column in SQL not in Group By

I have been trying to find some info on how to select a non-aggregate column that is not contained in the Group By statement in SQL, but nothing I've found so far seems to answer my question. I have a table with three columns that I want from it. One is a create date, one is a ID that groups the records by a particular Claim ID, and the final is the PK. I want to find the record that has the max creation date in each group of claim IDs. I am selecting the MAX(creation date), and Claim ID (cpe.fmgcms_cpeclaimid), and grouping by the Claim ID. But I need the PK from these records (cpe.fmgcms_claimid), and if I try to add it to my select clause, I get an error. And I can't add it to my group by clause because then it will throw off my intended grouping. Does anyone know any workarounds for this? Here is a sample of my code:
Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid
from Filteredfmgcms_claimpaymentestimate cpe
where cpe.createdon < 'reportstartdate'
group by cpe.fmgcms_cpeclaimid
This is the result I'd like to get:
Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid, cpe.fmgcms_claimid
from Filteredfmgcms_claimpaymentestimate cpe
where cpe.createdon < 'reportstartdate'
group by cpe.fmgcms_cpeclaimid
The columns in the result set of a select query with group by clause must be:
an expression used as one of the group by criteria , or ...
an aggregate function , or ...
a literal value
So, you can't do what you want to do in a single, simple query. The first thing to do is state your problem statement in a clear way, something like:
I want to find the individual claim row bearing the most recent
creation date within each group in my claims table
Given
create table dbo.some_claims_table
(
claim_id int not null ,
group_id int not null ,
date_created datetime not null ,
constraint some_table_PK primary key ( claim_id ) ,
constraint some_table_AK01 unique ( group_id , claim_id ) ,
constraint some_Table_AK02 unique ( group_id , date_created ) ,
)
The first thing to do is identify the most recent creation date for each group:
select group_id ,
date_created = max( date_created )
from dbo.claims_table
group by group_id
That gives you the selection criteria you need (1 row per group, with 2 columns: group_id and the highwater created date) to fullfill the 1st part of the requirement (selecting the individual row from each group. That needs to be a virtual table in your final select query:
select *
from dbo.claims_table t
join ( select group_id ,
date_created = max( date_created )
from dbo.claims_table
group by group_id
) x on x.group_id = t.group_id
and x.date_created = t.date_created
If the table is not unique by date_created within group_id (AK02), you you can get duplicate rows for a given group.
You can do this with PARTITION and RANK:
select * from
(
select MyPK, fmgcms_cpeclaimid, createdon,
Rank() over (Partition BY fmgcms_cpeclaimid order by createdon DESC) as Rank
from Filteredfmgcms_claimpaymentestimate
where createdon < 'reportstartdate'
) tmp
where Rank = 1
The direct answer is that you can't. You must select either an aggregate or something that you are grouping by.
So, you need an alternative approach.
1). Take you current query and join the base data back on it
SELECT
cpe.*
FROM
Filteredfmgcms_claimpaymentestimate cpe
INNER JOIN
(yourQuery) AS lookup
ON lookup.MaxData = cpe.createdOn
AND lookup.fmgcms_cpeclaimid = cpe.fmgcms_cpeclaimid
2). Use a CTE to do it all in one go...
WITH
sequenced_data AS
(
SELECT
*,
ROW_NUMBER() OVER (PARITION BY fmgcms_cpeclaimid ORDER BY CreatedOn DESC) AS sequence_id
FROM
Filteredfmgcms_claimpaymentestimate
WHERE
createdon < 'reportstartdate'
)
SELECT
*
FROM
sequenced_data
WHERE
sequence_id = 1
NOTE: Using ROW_NUMBER() will ensure just one record per fmgcms_cpeclaimid. Even if multiple records are tied with the exact same createdon value. If you can have ties, and want all records with the same createdon value, use RANK() instead.
You can join the table on itself to get the PK:
Select cpe1.PK, cpe2.MaxDate, cpe1.fmgcms_cpeclaimid
from Filteredfmgcms_claimpaymentestimate cpe1
INNER JOIN
(
select MAX(createdon) As MaxDate, fmgcms_cpeclaimid
from Filteredfmgcms_claimpaymentestimate
group by fmgcms_cpeclaimid
) cpe2
on cpe1.fmgcms_cpeclaimid = cpe2.fmgcms_cpeclaimid
and cpe1.createdon = cpe2.MaxDate
where cpe1.createdon < 'reportstartdate'
Thing I like to do is to wrap addition columns in aggregate function, like max().
It works very good when you don't expect duplicate values.
Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid, MAX(cpe.fmgcms_claimid) As fmgcms_claimid
from Filteredfmgcms_claimpaymentestimate cpe
where cpe.createdon < 'reportstartdate'
group by cpe.fmgcms_cpeclaimid
What you are asking, Sir, is as the answer of RedFilter.
This answer as well helps in understanding why group by is somehow a simpler version or partition over:
SQL Server: Difference between PARTITION BY and GROUP BY
since it changes the way the returned value is calculated and therefore you could (somehow) return columns group by can not return.
You can use as below,
Select X.a, X.b, Y.c from (
Select X.a as a, sum (b) as sum_b from name_table X
group by X.a)X
left join from name_table Y on Y.a = X.a
Example;
CREATE TABLE #products (
product_name VARCHAR(MAX),
code varchar(3),
list_price [numeric](8, 2) NOT NULL
);
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
INSERT INTO #products VALUES ('Dinding', 'ADE', 2000)
INSERT INTO #products VALUES ('Kaca', 'AKB', 2000)
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
--SELECT * FROM #products
SELECT distinct x.code, x.SUM_PRICE, product_name FROM (SELECT code, SUM(list_price) as SUM_PRICE From #products
group by code)x
left join #products y on y.code=x.code
DROP TABLE #products

sql query - filtering duplicate values to create report

I am trying to list all the duplicate records in a table. This table does not have a Primary Key and has been specifically created only for creating a report to list out duplicates. It comprises of both unique and duplicate values.
The query I have so far is:
SELECT [OfficeCD]
,[NewID]
,[Year]
,[Type]
FROM [Test].[dbo].[Duplicates]
GROUP BY [OfficeCD]
,[NewID]
,[Year]
,[Type]
HAVING COUNT(*) > 1
This works right and gives me all the duplicates - that is the number of times it occurs.
But I want to display all the values in my report of all the columns. How can I do that without querying for each record separately?
For example:
Each table has 10 fields and [NewID] is the field which is occuring multiple times.I need to create a report with all the data in all the fields where newID has been duplicated.
Please help.
Thank you.
You need a subquery:
SELECT * FROM yourtable
WHERE NewID IN (
SELECT NewID FROM yourtable
GROUP BY OfficeCD,NewID,Year,Type
HAVING Count(*)>1
)
Additionally you might want to check your tags: You tagged mysql, but the Syntax lets me think you mean sql-server
Try this:
SELECT * FROM [Duplicates] WHERE NewID IN
(
SELECT [NewID] FROM [Duplicates] GROUP BY [NewID] HAVING COUNT(*) > 1
)
select d.*
from Duplicates d
inner join (
select NewID
from Duplicates
group by NewID
having COUNT(*) > 1
) dd on d.NewID = dd.NewID