I'm probably missing something simple here. I have this first table:
CREATE TABLE [Orgnzs] (
[id] INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
[nm] NVARCHAR(256)
);
and then also several tables that are all created as such (all having the same structure):
-- WLog_* tables are all created as such
CREATE TABLE [WLog_1] (
[id] BIGINT NOT NULL IDENTITY(1,1) PRIMARY KEY,
[huid] UNIQUEIDENTIFIER,
[dtin] BIGINT,
[dtout] BIGINT,
[cnm] NVARCHAR(15),
[batt] TINYINT,
[pwrop] TINYINT,
[pst] INT,
[flgs] INT,
[ppocs] NVARCHAR(1024),
[ppocu] NVARCHAR(1024),
[por] NVARCHAR(1024)
);
and a similar set of tables, without last 3 columns of the table above:
-- ULog_* tables are all created as such
CREATE TABLE [ULog_1] (
[id] BIGINT NOT NULL IDENTITY(1,1) PRIMARY KEY,
[huid] UNIQUEIDENTIFIER,
[dtin] BIGINT,
[dtout] BIGINT,
[cnm] NVARCHAR(15),
[batt] TINYINT,
[pwrop] TINYINT,
[pst] INT,
[flgs] INT
);
My goal is to select records from arbitrary set of WLog_* and ULog_* tables, and limit it by manageable number of elements (for page layout) for which I also need to know the total count of records found.
So I do selection as such:
SELECT b.[id] AS evtID,
b.[huid] as huid,
b.[dtin] as dtin,
b.[dtout] as dtout,
b.[cnm] as cnm,
b.[batt] as batt,
b.[pwrop] as pwrop,
b.[pst] as pst,
b.[flgs] as flgs,
b.[ppocs] as ppocs,
b.[ppocu] as ppocu,
b.[por] as por,
b.[orgID] as orgID,
b.[wLg] as wLg,
orgz.[nm] as orgNm
, COUNT_BIG(*) as allRecordsFound
FROM (
-- next also specify the column(s) to sort by
SELECT *, ROW_NUMBER() OVER (ORDER BY [dtin], [cnm] ASC) AS rw FROM (
SELECT *, 1 AS orgID, 1 AS wLg
FROM [WLog_1]
UNION ALL
SELECT *, 2 AS orgID, 1 AS wLg
FROM [WLog_2]
UNION ALL
SELECT *, NULL AS [ppocs], NULL AS [ppocu], NULL AS [por], 1 AS orgID, 0 AS wLg
FROM [ULog_1]
) a
WHERE [pst]&1=1 OR [pst]=67
) b
LEFT JOIN [Orgnzs] AS orgz ON orgID=orgz.[id]
WHERE rw >= 2 AND rw <= 4 -- restrict for a page only
which unfortunately fails on the COUNT_BIG(*) as allRecordsFound line with the following error:
Column 'b.id' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.
I haven't used SQL Server for a while, can someone suggest what am I missing here?
PS. For a test purpose I made a Fiddle to try it out.
Use this instead:
count(*) over() as allRecordsFound
You can mix window aggregation function in select statement whithout grouping.
Related
I am joining two common table expressions (cte) based on an id created within each cte using ROW_NUMBER(). The resulting execution plan includes a Merge Join where the Estimated Rows are 13,530,000,000 in my case; and the actual number of rows ends up being about 13,000.
Below is an example of what I am trying to do, and this results in a similar execution plan with 1,200,000,000 estimated rows in the Merge Join, and 12,000 actual rows.
I am stuck understanding why what seems like a simple join is creating a Cartesian product.
IF OBJECT_ID('tempdb..#Product') IS NOT NULL DROP TABLE #Product;
IF OBJECT_ID('tempdb..#Product_Id') IS NOT NULL DROP TABLE #Product_Id;
CREATE TABLE #Product (
[rowId] int identity primary key,
[id] int
)
CREATE TABLE #Product_Id (
[id] int primary key
)
DECLARE #Id int
SET #Id = 500000
WHILE #Id <= 600000
BEGIN
INSERT INTO #Product_Id
VALUES (#Id)
SET #Id += 1
END
SET #Id = 1
WHILE #Id <= 12000
BEGIN
INSERT INTO #Product
VALUES (NULL)
SET #Id += 1
END
WITH
PRODUCT_ID_CTE AS (
SELECT [id],
ROW_NUMBER() OVER(ORDER BY [id]) AS [rn]
FROM #Product_Id
),
PRODUCT_CTE AS (
SELECT [id],
ROW_NUMBER() OVER(ORDER BY [rowId]) AS [rn]
FROM #Product
)
SELECT ISNULL(a.[id], b.[id]) AS [id]
FROM PRODUCT_CTE a
JOIN PRODUCT_ID_CTE b
ON a.[rn] = b.[rn]
Execution plan with CTE
Execution plan with sub queries
SELECT
#MaxSeq = (CASE
WHEN (SELECT COUNT(*) FROM app_Attachments
WHERE app_Attachments.AppId = #appID) <= 0
THEN 1
ELSE (SELECT (MAX(seq)+1)
FROM app_Attachments
WHERE app_Attachments.AppId = #appID)
END)
DECLARE #Id INT;
SELECT #Id = (COALESCE((SELECT MAX(Id)+1 FROM app_Attachments), 1))
INSERT INTO app_Attachments (Id, AppID, AttName, AttContentType, AttData, AddedBy, AddedDate, Seq)
SELECT
#Id, AppId, ImgNames, ImgType, Bytes, #AddedBy, #AddedDate, #MaxSeq
FROM
#Attachments --user defined table
CREATE TYPE [dbo].[AppsAttachments] AS TABLE
(
[AppId] [INT] NULL,
[Bytes] [VARBINARY](MAX) NULL,
[ImgNames] [NVARCHAR](MAX) NULL,
[ImgType] [NVARCHAR](200) NULL
)
Insert into table using stored procedure that has user defined table as parameter only success if table passed has one row, it was working well when the primary key is set as identity, after I changed the primary key into manual integer to be entered the problem occurred
if Id is not identity, then you need to ensure the Id is not duplicates. Use Row_number() to generate a running sequence of number
insert into app_Attachments (Id,AppID,AttName,AttContentType,AttData,AddedBy,AddedDate,Seq)
select #Id + ROW_NUMBER() OVER (ORDER BY AppId) - 1,
AppId,
ImgNames,
ImgType,
Bytes,
#AddedBy,
#AddedDate,
#MaxSeq
from #Attachments --user defined table
if you also need to increase the Seq as well, add a row_number() to the query
Specifically I'm using SQL Server Compact 4.0, if that makes a difference.
I have 3 tables (note,userTable,verse). the user and verse table have no correlation except in this note table, so I can't do a single subquery joining the two tables.
INSERT INTO [note]
([verse_id]
,[user_id]
,[text]
,[date_created]
,[date_modified])
VALUES
( (SELECT Id FROM verse
WHERE volume_lds_url = 'ot'
AND book_lds_url = 'gen'
AND chapter_number = 8
AND verse_number = 16)
, (SELECT Id FROM userTable
WHERE username = 'canichols2')
,'test message'
,GETDATE()
,GETDATE());
GO
As far as I can tell, the statement should work.
The outer statements works fine if i hard code the Foreign Key values, and each of the subqueries work as they should and only return one column and one row each.
Error Message:There was an error parsing the query. [ Token line number = 8,Token line offset = 14,Token in error = SELECT ]
So It doesn't like the subquery in a scalar values clause, but I Can't figure out how to use a
INSERT INTO .... SELECT ....
statement with the 2 different tables.
Table Definitions
Since #Prasanna asked for it, here's the deffinitions
CREATE TABLE [userTable] (
[Id] int IDENTITY (1,1) NOT NULL
, [username] nvarchar(100) NOT NULL
, [email] nvarchar(100) NOT NULL
, [password] nvarchar(100) NULL
);
GO
ALTER TABLE [userTable] ADD CONSTRAINT [PK_user] PRIMARY KEY ([Id]);
GO
CREATE TABLE [note] (
[Id] int IDENTITY (1,1) NOT NULL
, [verse_id] int NULL
, [user_id] int NULL
, [text] nvarchar(4000) NOT NULL
, [date_created] datetime DEFAULT GETDATE() NOT NULL
, [date_modified] datetime NULL
);
GO
ALTER TABLE [note] ADD CONSTRAINT [PK_note] PRIMARY KEY ([Id]);
GO
CREATE TABLE [verse] (
[Id] int IDENTITY (1,1) NOT NULL
, [volume_id] int NULL
, [book_id] int NULL
, [chapter_id] int NULL
, [verse_id] int NULL
, [volume_title] nvarchar(100) NULL
, [book_title] nvarchar(100) NULL
, [volume_long_title] nvarchar(100) NULL
, [book_long_title] nvarchar(100) NULL
, [volume_subtitle] nvarchar(100) NULL
, [book_subtitle] nvarchar(100) NULL
, [volume_short_title] nvarchar(100) NULL
, [book_short_title] nvarchar(100) NULL
, [volume_lds_url] nvarchar(100) NULL
, [book_lds_url] nvarchar(100) NULL
, [chapter_number] int NULL
, [verse_number] int NULL
, [scripture_text] nvarchar(4000) NULL
);
GO
ALTER TABLE [verse] ADD CONSTRAINT [PK_scriptures] PRIMARY KEY ([Id]);
GO
I'm aware it's not in the 1st normal form or anything, But that's how it was given to me, and I didn't feel like dividing it up into multiple tables.
SubQuery Results
To show the results and how there's only 1 row.
SELECT Id FROM WHERE volume_lds_url = 'ot'
AND book_lds_url = 'gen'
AND chapter_number = 8
AND verse_number = 16
Id
200
And the second subquery
SELECT Id FROM userTable
WHERE username = 'canichols2'
Id
1
Attention: The target system is SQL-Server-Compact-CE-4
This smaller brother seems not to support neither sub-selects as scalar values, nor declared variables. Find details in comments...
Approach 1
As long as you can be sure, that the sub-select returns exactly one scalar value, it should be easy to transform your VALUES to a SELECT. Try this:
INSERT INTO [note]
([verse_id]
,[user_id]
,[text]
,[date_created]
,[date_modified])
SELECT
(SELECT Id FROM verse
WHERE volume_lds_url = 'ot'
AND book_lds_url = 'gen'
AND chapter_number = 8
AND verse_number = 16)
, (SELECT Id FROM userTable
WHERE username = 'canichols2')
,'test message'
,GETDATE()
,GETDATE();
Approach 2
No experience with Compact editions of SQL-Server, but you might try this:
DECLARE #id1 INT=(SELECT Id FROM verse
WHERE volume_lds_url = 'ot'
AND book_lds_url = 'gen'
AND chapter_number = 8
AND verse_number = 16);
DECLARE #id2 INT=(SELECT Id FROM userTable
WHERE username = 'canichols2');
INSERT INTO [note]
([verse_id]
,[user_id]
,[text]
,[date_created]
,[date_modified])
SELECT #id1
,#id2
,'test message'
,GETDATE()
,GETDATE();
Hey so I am new to sql and am building an inventory management system. So for the database i am getting stuck at this point where I need to insert the various user id's to different Teams in the company, hence my problem arises when I am trying to assign multiple int values to a particular team.The DB is made in a manner where it requires a TeamId and the corresponding UserId's to go with it.
Possible this be helpful for you -
DECLARE #temp TABLE (ID INT)
-- For 2008 and higher
INSERT INTO #temp (ID)
VALUES (1), (2), (3)
-- For 2005 and higher
INSERT INTO #temp (ID)
SELECT ID
FROM (
SELECT ID = 4
UNION ALL
SELECT 5
UNION ALL
SELECT 6
) t
SELECT *
FROM #temp
Update (comment #Sivakumar: "1,19 is not an integer. It is a varchar."):
DECLARE #temp TABLE (txt varchar(500))
INSERT INTO #temp (txt)
VALUES ('1,19'), ('2,18')
SELECT t.c.value('.', 'INT')
FROM (
SELECT txml = CAST('<t>' + REPLACE(txt, ',', '</t><t>') + '</t>' AS XML)
FROM #temp
) a
CROSS APPLY txml.nodes('/t') AS t(c)
It sounds like a one-to-many relationship: a Team can have zero or more Users.
So create a foreign key column in User that references the Team primary key.
Something like this (check my syntax):
create table team (
id int not null auto_increment,
primary key(id);
);
create table user (
id int not null auto_increment,
tid int,
primary key(id),
foreign key tid references(team);
);
select *
from team t
join user u
on t.id = u.tid;
I have 3 tables similar to the sctructure below
CREATE TABLE [dbo].[EmpBasic](
[EmpID] [int] IDENTITY(1,1) NOT NULL Primary Key,
[Name] [varchar](50),
[Address] [varchar](50)
)
CREATE TABLE [dbo].[EmpProject](
[EmpID] [int] NOT NULL primary key, // referencing column with EmpBasic
[EmpProject] [varchar](50) )
CREATE TABLE [dbo].[EmpFull_Temp](
[ObjectID] [int] IDENTITY(1,1) NOT NULL Primary Key,
[T1Name] [varchar](50) ,
[T1Address] [varchar](50) ,
[T1EmpProject] [varchar](50)
)
The EmpFull_Temp table has the records with a dummy object ID column... I want to populate the first 2 tables with the records in this table... But with EmpID as a reference between the first 2 tables.
I tried this in a stored procedure...
Create Table #IDSS (EmpID bigint, objID bigint)
Insert into EmpBasic
output Inserted.EmpID, EmpFull_Temp.ObjectID
into #IDSS
Select T1Name, T1Address from EmpFull_Temp
Where ObjectID < 106
Insert into EmpProject
Select A.EmpID, B.T1EmpProject from #IDSS as A, EmpFull_Temp as B
Where A.ObjID = B.ObjectID
But it says.. The multi-part identifier "EmpFull_Temp.ObjectID" could not be bound.
Could you please help me in achieving this...
Edit : There is no guarantee that [Name]+[Address] would be unique across [EmpBasic] Table
With your EmpProject join table, you probably don't want the primary key constraint on only the EmpID column
DECLARE #Count int
DECLARE #NextEmpID int
DECLARE #StartObjectID int
DECLARE #EndObjectID int
-- range of IDs to transfer (inclusive)
SET #StartObjectID = 1
SET #EndObjectID = 105
BEGIN TRAN
-- lock tables so IDENT_CURRENT is valid
SELECT #Count = COUNT(*) FROM [EmpBasic] WITH (TABLOCKX, HOLDLOCK)
SELECT #Count = COUNT(*) FROM [EmpProject] WITH (TABLOCKX, HOLDLOCK)
SELECT #NextEmpID = IDENT_CURRENT('EmpBasic')
SET IDENTITY_INSERT [EmpBasic] ON
INSERT [EmpBasic] ([EmpID], [Name], [Address])
SELECT #NextEmpID + ROW_NUMBER() OVER(ORDER BY ObjectID), [T1Name], [T1Address]
FROM [EmpFull_Temp]
WHERE [ObjectID] BETWEEN #StartObjectID AND #EndObjectID
SET IDENTITY_INSERT [EmpBasic] OFF
INSERT [EmpProject]([EmpID], [EmpProject])
SELECT #NextEmpID + ROW_NUMBER() OVER(ORDER BY ObjectID), [T1EmpProject]
FROM [EmpFull_Temp]
WHERE [ObjectID] BETWEEN #StartObjectID AND #EndObjectID
COMMIT TRAN
The solution to this problem depends on whether the "parent" table (i.e. the one with the IDENTITY column) has a natural key (i.e. one or more fields which, when combined, are guaranteed to be unique, other than the surrogate primary key).
For example, in this case, is the combinaton of Name and Address aways going to be unique?
If the answer is yes then you can simply insert into EmpBasic without bothering to output and store the generated IDs. You can then insert into EmpProject joining back on to EmpBasic using the natural key (e.g. name and address) to fnd the correct EmpID.
Insert into EmpBasic
Select T1Name, T1Address from EmpFull_Temp
Where ObjectID < 106
Insert into EmpProject
Select A.EmpID, B.T1EmpProject from EmpBasic as A, EmpFull_Temp as B
Where A.Name = B.Name And A.Address = B.Address
If the answer is no then there is no easy solution I know of - in SQL Server 2005 (I've no idea if this is any different in 2008), it's not possible to OUTPUT values that are not inserted. I've got around this issue in the past by using one of the other fields (e.g. Name) to temporarily store the original ID (in this case, ObjectID), use that to join when inserting the child records as described above and then gone back to update the parent records o remove/replace the temporary values. It's not nice but I've not found a better way.
Insert into EmpBasic
Select cast(ObjectID as varchar(50)) as name, T1Address from EmpFull_Temp
Where ObjectID < 106
Insert into EmpProject
Select A.EmpID, B.T1EmpProject from EmpBasic as A, EmpFull_Temp as B
Where A.Name = cast(B.ObjectID as varchar(50))
Update EmpBasic
Set Name = B.T1Name
from EmpBasic as A, EmpFull_Temp as B
Where A.Name = cast(B.ObjectID as varchar(50))
Please note: I've not tested the sample SQL given above but I hope it gives you an idea of how you might approach this.
Add an ObjectID column to the EmpBasic table to facilitate the data transfer then drop it when you're done. I'm assuming this is a one-time operation, I don't recommend adding and dropping a column if this is on-going
I have used the Stack Exchange Data Explorer to investigate alternative solutions. The only one with promise at the moment is shown here. It is effectively #ScotHauder's answer, except using a temporary table that has the ObjectID column and using IDENTITY_INSERT to move the generated EmpId values into EmpBasic.
If you have to do this multiple times you need to get the EmpBasic_Temp EmpId IDENTITY starting value to be Max(EmpBasic.EmpID)+1.