Using a case statement in the group by - sql

I have the below sql. I am wanting my results to be grouped if the boolean is checked 0, but not grouped if the boolean is checked 1. Is the code below a good way of doing this? I feel like it should work but it is throwing the error "InvoicePeriodID is invalid in the select list because it is not contained in an aggraagte function or group by" Any advice?
----insert invoices for rebates grouped by date, address, contract, rebate note, and order type
declare #invoices table(InvoicePeriodID int, InvoiceStartDate datetime, InvoiceEndDate datetime, JDEAddressNo float, ContractID int, RebateNoteID int, JDEOrderType char(2), RebateInvoiceID int)
insert #invoices (InvoicePeriodID , InvoiceStartDate , InvoiceEndDate , JDEAddressNo , ContractID , RebateNoteID, JDEOrderType)
select
i.InvoicePeriodID
, i.InvoiceStartDate
, i.InvoiceEndDate
, i.JDEAddressNo
, i.ContractID
, i.RebateNoteID
, i.JDEOrderType
from
#inv i
group by
case i.InvoiceSeparately
when 1 then null
when 0 then i.InvoicePeriodID
end
, case i.InvoiceSeparately
when 1 then null
when 0 then i.InvoiceStartDate
end
, case i.InvoiceSeparately
when 1 then null
when 0 then i.InvoiceEndDate
end
, case i.InvoiceSeparately
when 1 then null
when 0 then i.JDEAddressNo
end
, case i.InvoiceSeparately
when 1 then null
when 0 then i.ContractID
end
, case i.InvoiceSeparately
when 1 then null
when 0 then i.RebateNoteId
end
, case i.InvoiceSeparately
when 1 then null
when 0 then i.JDEOrderType
end

I think it is more readable and easier to do what you want this way
select
i.InvoicePeriodID
, i.InvoiceStartDate
, i.InvoiceEndDate
, i.JDEAddressNo
, i.ContractID
, i.RebateNoteID
, i.JDEOrderType
from
#inv i
WHERE i.InvoiceSeparately = 0
group BY i.InvoicePeriodID
,i.InvoiceStartDate
,i.InvoiceEndDate
, i.JDEAddressNo
, i.ContractID
,i.RebateNoteId
, i.JDEOrderType
UNION ALL
select
i.InvoicePeriodID
, i.InvoiceStartDate
, i.InvoiceEndDate
, i.JDEAddressNo
, i.ContractID
, i.RebateNoteID
, i.JDEOrderType
from
#inv i
WHERE i.InvoiceSeparately = 1

Related

TSQL Inserting values based on integer results from select statement

I'm running the following query:
select
max(count) Max
from
(select
count(iStockID) Count
from
_etblInvJrBatchLines
group by
iStockID) X
As you know, the result of this is an integer; in this case, the result was 5.
Based on the above result, I need to insert generic values into another table, that looks like this:
INSERT INTO _etblInvJrBatches
(
cInvJrNumber -- IJ0001 Plus 1
, cInvJrDescription -- Inventory Journal Batch
, cInvJrReference -- IJR10001 Plus 1
, iCreateAgentID -- 1
, bClearAfterPost -- 1
, bAllowDupRef -- 1
, bAllowEditGLContra -- 0
, iNewLineDateOpt -- 0
, iNewLineRefOpt -- 0
, cNewLineRefDef -- ''
, bNewLineRefInc -- 0
, iNewLineDescOpt -- 0
, cNewLineDescDef -- ''
, bNewLineDescInc -- 0
, iNewLineProjectOpt -- 0
, iNewLineProjectDefID -- 0
, iNewLineWarehouseOpt -- 0
, iNewLineWarehouseDefID -- 0
, bJustCleared -- 0
, iTransactionCode -- 31 (select TrCodeID where TrCode = 'ADJ')
)
SELECT
'IJ000' -- Plus 1
, 'Inventory Journal Batch'
, 'IJR1000' -- Plus 1
, 1
, 1
, 1
, 0
, 0
, 0
, ''
, 0
, 0
, ''
, 0
, 0
, 0
, 0
, 0
, 0
, (select idTrCodes from TrCodes where Code = 'ADJ')
The only problem is, it only inserts this once.
How do I insert this 5 times based on the results I get from my first select statement?
In other words, if the integer result is 24, it needs to import / insert the above 24 times.
Thank you for assisting.
Attie.
Cant you just use a tally table?
declare #count int
set #count = (select
max(count) Max
from
(select
count(iStockID) Count
from
_etblInvJrBatchLines
group by
iStockID) X) --Hardcoded 10
IF OBJECT_ID('tempdb..#tally') IS NOT NULL
/*Then it exists*/
DROP TABLE #tally
SELECT TOP (#count) --equates to more than 30 years of dates
IDENTITY(INT,1,1) AS N
INTO #tally
FROM Master.dbo.SysColumns sc1,
Master.dbo.SysColumns sc2
--PRINT #count
INSERT INTO _etblInvJrBatches
(
cInvJrNumber -- IJ0001 Plus 1
, cInvJrDescription -- Inventory Journal Batch
, cInvJrReference -- IJR10001 Plus 1
, iCreateAgentID -- 1
, bClearAfterPost -- 1
, bAllowDupRef -- 1
, bAllowEditGLContra -- 0
, iNewLineDateOpt -- 0
, iNewLineRefOpt -- 0
, cNewLineRefDef -- ''
, bNewLineRefInc -- 0
, iNewLineDescOpt -- 0
, cNewLineDescDef -- ''
, bNewLineDescInc -- 0
, iNewLineProjectOpt -- 0
, iNewLineProjectDefID -- 0
, iNewLineWarehouseOpt -- 0
, iNewLineWarehouseDefID -- 0
, bJustCleared -- 0
, iTransactionCode -- 31 (select TrCodeID where TrCode = 'ADJ')
)
select N, 'IJ000' -- Plus 1
, 'Inventory Journal Batch'
, 'IJR1000' -- Plus 1
, 1
, 1
, 1
, 0
, 0
, 0
, ''
, 0
, 0
, ''
, 0
, 0
, 0
, 0
, 0
, 0 from #tally where n >0 and n <= #count
Result
There are many ways to accomplish this.
INSERT only inserts one row into the target table. Ultimately you are going to have to INSERT in a loop.
Possible solutions...
Do the looping in the database...
declare #count int = (select
max(count) Max
from
(select
count(iStockID) Count
from
_etblInvJrBatchLines
group by
iStockID) X)
declare #increment int =1
while #increment <= #count
{
-- do your insert here...
#increment = #increment +1
}
Do the looping in your client code.
Retrieve the count value from your initial query
For increment = 1 to #count
'execute SQL to do insert here...
Next increment
Or better (as #scsimon hinted at)...
For increment = 1 to #count
'build the VALUES () clauses for your insert statement...
Next
'execute your insert statement
I didn't realize that T-SQL allowed multiple VALUES clauses in an INSERT. Thank you #scsimon!
If it's me, I'm doing all of this in a client with code, not in the database. I'm old school, and I don't think that solutions like this scale well when built in the database as in my first example.
Thank you everyone for your contribution!
Special thanks to #Thomas as his advice worked the best in my environment.
I altered his script a little bit to accommodate the reference numbering:
declare #count int
set #count = (select
max(count) Max
from
(select
count(iStockID) Count
from
_etblInvJrBatchLines
group by
iStockID) X) --Hardcoded 10
IF OBJECT_ID('tempdb..#tally') IS NOT NULL
/*Then it exists*/
DROP TABLE #tally
SELECT TOP (#count) --equates to more than 30 years of dates
IDENTITY(INT,1,1) AS N
INTO #tally
FROM Master.dbo.SysColumns sc1,
Master.dbo.SysColumns sc2
--PRINT #count
INSERT INTO _etblInvJrBatches
(
cInvJrNumber -- IJ0001
, cInvJrDescription -- Inventory Journal Batch
, cInvJrReference -- IJR10001
, iCreateAgentID -- 1
, bClearAfterPost -- 1
, bAllowDupRef -- 1
, bAllowEditGLContra -- 0
, iNewLineDateOpt -- 0
, iNewLineRefOpt -- 0
, cNewLineRefDef -- ''
, bNewLineRefInc -- 0
, iNewLineDescOpt -- 0
, cNewLineDescDef -- ''
, bNewLineDescInc -- 0
, iNewLineProjectOpt -- 0
, iNewLineProjectDefID -- 0
, iNewLineWarehouseOpt -- 0
, iNewLineWarehouseDefID -- 0
, bJustCleared -- 0
, iTransactionCode -- 31 (select idTrCodes from TrCodes where Code = 'ADJ')
)
select
'IJ000' + cast(N as varchar)
, 'Inventory Journal Batch'
, 'IJR1000' + cast(N as varchar)
, 1
, 1
, 1
, 0
, 0
, 0
, ''
, 0
, 0
, ''
, 0
, 0
, 0
, 0
, 0
, 0
, (select idTrCodes from TrCodes where Code = 'ADJ')
from #tally where n >0 and n <= #count
This worked like a charm!
See results:Results

SQL - Complex Stored Procedure need to change value of 'case when' from integer to VarChar after being counted

I have a website for an NFL Pool. I'm able to display User Picks and the amount of Wins user has. As of now my CASE WHEN is using integer as win or lost. I would like to change it to be where 1 = 'Won' and 0 = 'Lost' but still count the amount of wins the user has.
Is this possible?
Thanks for any help.
My code:
DECLARE #commondata TABLE (FullName VARCHAR(30), Game_1 VARCHAR(30), Game_2 VARCHAR(30), Game_3 VARCHAR(30), Game_4 VARCHAR(30), Game_5 VARCHAR(30),
GameResults_1 INT, GameResults_2 INT, GameResults_3 INT, GameResults_4 INT, GameResults_5 INT)
INSERT INTO #commondata (FullName, Game_1, Game_2, Game_3, Game_4, Game_5,
GameResults_1, GameResults_2 , GameResults_3, GameResults_4, GameResults_5)
SELECT UserPicks.FullName, UserPicks.Game_1, UserPicks.Game_2, UserPicks.Game_3, UserPicks.Game_4, UserPicks.Game_5,
(CASE WHEN UserPicks.Game_1 = WeeklyResults.GameResults_1 THEN 1 ELSE 0 END) AS GameResult_1,
(CASE WHEN UserPicks.Game_2 = WeeklyResults.GameResults_2 THEN 1 ELSE 0 END) AS GameResult_2,
(CASE WHEN UserPicks.Game_3 = WeeklyResults.GameResults_3 THEN 1 ELSE 0 END) AS GameResult_3,
(CASE WHEN UserPicks.Game_4 = WeeklyResults.GameResults_4 THEN 1 ELSE 0 END) AS GameResult_4,
(CASE WHEN UserPicks.Game_5 = WeeklyResults.GameResults_5 THEN 1 ELSE 0 END) AS GameResult_5
FROM UserPicks
JOIN WeeklyResults ON UserPicks.Week = WeeklyResults.Week
WHERE WeeklyResults.Week = 'Week1'
-- Unpivot the table.
(SELECT FullName, Game_1, Game_2, Game_3, Game_4, Game_5, SUM(Points) As Total
FROM
(SELECT *
FROM #commondata) pvt
UNPIVOT
(Points FOR Game IN
(GameResults_1, GameResults_2, GameResults_3, GameResults_4, GameResults_5)
)AS Total
GROUP BY FullName, Game_1, Game_2, Game_3, Game_4, Game_5)
Try this, I took the liberty to reformat, remove redundant lines and use table acronyms to make it easier to read/understand:
DECLARE #commondata TABLE (FullName VARCHAR(30)
, Game_1 VARCHAR(30)
, Game_2 VARCHAR(30)
, Game_3 VARCHAR(30
, Game_4 VARCHAR(30)
, Game_5 VARCHAR(30)
, GameResults_1 VARCHAR(4)
, GameResults_2 VARCHAR(4)
, GameResults_3 VARCHAR(4)
, GameResults_4 VARCHAR(4)
, GameResults_5 VARCHAR(4));
INSERT INTO #commondata
SELECT UP.FullName
, UP.Game_1
, UP.Game_2
, UP.Game_3
, UP.Game_4
, UP.Game_5
, IIF(UP.Game_1 = WR.GameResults_1, 'Won', 'Lost') AS GameResult_1
, IIF(UP.Game_2 = WR.GameResults_2, 'Won', 'Lost') AS GameResult_2
, IIF(UP.Game_3 = WR.GameResults_3, 'Won', 'Lost') AS GameResult_3
, IIF(UP.Game_4 = WR.GameResults_4, 'Won', 'Lost') AS GameResult_4
, IIF(UP.Game_5 = WR.GameResults_5, 'Won', 'Lost') AS GameResult_5
FROM UserPicks UP
JOIN WeeklyResults WR ON UP.Week = WR.Week
WHERE WR.Week = 'Week1';
-- Unpivot the table.
SELECT FullName
, Game_1
, Game_2
, Game_3
, Game_4
, Game_5
, SUM(IIF(Result='Won', 1, 0)) As Total
FROM #commondata
UNPIVOT (
Result FOR Game IN (GameResults_1
, GameResults_2
, GameResults_3
, GameResults_4
, GameResults_5)
) AS Total
GROUP BY FullName
, Game_1
, Game_2
, Game_3
, Game_4
, Game_5;

Aggregating different rows in one column SQL Query

Sorry, I didn't come up with a good title for the question, so feel free to change it accordingly.
I may describe my question with a minimal example in MS SQL server 2012:
create table #tmp
(
RowID varchar(10),
SectionCode int,
SectionName varchar(10)
)
insert into #tmp values('Record1' , 1 , 'AB');
insert into #tmp values('Record1' , 2 , 'CD');
insert into #tmp values('Record1' , 3 , 'EF');
insert into #tmp values('Record2' , 1 , 'AB');
insert into #tmp values('Record2' , 4 , 'GH');
insert into #tmp values('Record2' , 5 , 'IJ');
insert into #tmp values('Record3' , 2 , 'CD');
insert into #tmp values('Record3' , 5 , 'IJ');
I am trying to create a one row per record result in which every section is a column and if there is a row associated with a section, the corresponding column value is increased. This is (not) what I want (the same record data on different rows)
select RowID,
case when SectionName = 'AB' then 1 else 0 end as [AB Section] ,
case when SectionName = 'CD' then 1 else 0 end as [CD Section] ,
case when SectionName = 'EF' then 1 else 0 end as [EF Section] ,
case when SectionName = 'GH' then 1 else 0 end as [GH Section] ,
case when SectionName = 'IJ' then 1 else 0 end as [IJ Section]
from #tmp
group by RowID , SectionName
which gives this output:
I need this:
Thanks in advance
You can use pivot for this as below and manipulate the values of sections however you want.
SELECT rowid
,CASE
WHEN ab IS NULL
THEN 0
ELSE 1
END AS ab
,CASE
WHEN cd IS NULL
THEN 0
ELSE 1
END AS cd
,CASE
WHEN ef IS NULL
THEN 0
ELSE 1
END AS ef
,CASE
WHEN gh IS NULL
THEN 0
ELSE 1
END AS gh
,CASE
WHEN ij IS NULL
THEN 0
ELSE 1
END AS ij
FROM (
SELECT *
FROM #tmp
PIVOT(MAX(Sectioncode) FOR Sectionname IN (
AB
,CD
,EF
,GH
,IJ
)) pvt
) tab
I think the result you shown is not correct for record id 2. ij of record id 2 should be 1.
I think you want this:
select RowID,
sum(case when SectionName = 'AB' then 1 else 0 end) as [AB Section] ,
sum(case when SectionName = 'CD' then 1 else 0 end) as [CD Section] ,
sum(case when SectionName = 'EF' then 1 else 0 end) as [EF Section] ,
sum(case when SectionName = 'GH' then 1 else 0 end) as [GH Section] ,
from #tmp
group by RowID;
That is, you need aggregation functions. And the group by should contain the columns that you want to define each row (i.e. only the RowId).

Sub Query not working properly

I am trying to insert result of subquery inside another temporary table. SubQuery works fine when i execute that only, but not when as subquery. It throws syntax error.
Error is :Incorrect syntax near ')'. It is on first line of subquery
DECLARE #TempT TABLE
(
RowID INT IDENTITY(1, 1) ,
Date DATETIME ,
Type NVARCHAR(MAX) ,
V_No INT ,
Chq_No INT ,
Description NVARCHAR(MAX) ,
Debit MONEY ,
Credit MONEY ,
voucher_type_no INT ,
status NVARCHAR(10) ,
Clr_Date DATETIME ,
Voucher_Id INT ,
Party_Name NVARCHAR(MAX) ,
DateYYYYMMDD DATETIME
)
DECLARE #i INT= 1
INSERT INTO #TempT
SELECT *
FROM ( SELECT v.date 'Date' ,
vt.voucher_type_shortname 'Type' ,
v.voucher_no 'V_No' ,
v.cheque_no 'Chq_No' ,
a.account_name 'Description' ,
( CASE WHEN SUM(v.amount) > 0 THEN SUM(v.amount)
ELSE 0
END ) Debit ,
( CASE WHEN SUM(v.amount) < 0 THEN SUM(-v.amount)
ELSE 0
END ) Credit ,
v.voucher_type_no ,
r.status ,
r.recon_date 'Clr_Date' ,
MIN(v.voucher_id) Voucher_Id ,
'' 'Party_Name' ,
CONVERT(VARCHAR(10), r.recon_date, 126) 'Date YYYY-MM-DD'
FROM voucher v
LEFT OUTER JOIN reconcilation r ON v.voucher_id = r.voucher_id
LEFT OUTER JOIN account a ON v.other_acno = a.account_no ,
voucher_type vt
WHERE v.voucher_type_no = vt.voucher_type_no
AND v.voucher_type_no > 0
AND v.other_acno = a.account_no
AND v.acc_year = 51
AND v.account_no = 10030
AND R.recon_date <= '2015-01-12'
AND R.recon_date >= '2009-04-01'
AND V.posted IN ( 1, 2 )
GROUP BY v.voucher_no ,
v.cheque_no ,
v.date ,
vt.voucher_type_shortname ,
a.account_name ,
v.voucher_type_no ,
r.status ,
r.recon_date
)
Use a alias name after the last bracket
DECLARE #TempT TABLE
(
RowID INT IDENTITY(1, 1) ,
Date DATETIME ,
Type NVARCHAR(MAX) ,
V_No INT ,
Chq_No INT ,
Description NVARCHAR(MAX) ,
Debit MONEY ,
Credit MONEY ,
voucher_type_no INT ,
status NVARCHAR(10) ,
Clr_Date DATETIME ,
Voucher_Id INT ,
Party_Name NVARCHAR(MAX) ,
DateYYYYMMDD DATETIME
)
DECLARE #i INT= 1
INSERT INTO #TempT
SELECT *
FROM ( SELECT v.date 'Date' ,
vt.voucher_type_shortname 'Type' ,
v.voucher_no 'V_No' ,
v.cheque_no 'Chq_No' ,
a.account_name 'Description' ,
( CASE WHEN SUM(v.amount) > 0 THEN SUM(v.amount)
ELSE 0
END ) Debit ,
( CASE WHEN SUM(v.amount) < 0 THEN SUM(-v.amount)
ELSE 0
END ) Credit ,
v.voucher_type_no ,
r.status ,
r.recon_date 'Clr_Date' ,
MIN(v.voucher_id) Voucher_Id ,
'' 'Party_Name' ,
CONVERT(VARCHAR(10), r.recon_date, 126) 'Date YYYY-MM-DD'
FROM voucher v
LEFT OUTER JOIN reconcilation r ON v.voucher_id = r.voucher_id
LEFT OUTER JOIN account a ON v.other_acno = a.account_no ,
voucher_type vt
WHERE v.voucher_type_no = vt.voucher_type_no
AND v.voucher_type_no > 0
AND v.other_acno = a.account_no
AND v.acc_year = 51
AND v.account_no = 10030
AND R.recon_date <= '2015-01-12'
AND R.recon_date >= '2009-04-01'
AND V.posted IN ( 1, 2 )
GROUP BY v.voucher_no ,
v.cheque_no ,
v.date ,
vt.voucher_type_shortname ,
a.account_name ,
v.voucher_type_no ,
r.status ,
r.recon_date
) TAB

How to insert unique value into non-identity field

I'm trying to do an insert into an established table which has a primary key fields and another field (call it field1) that is unique (this other unique field has a unique constraint preventing my inserts). Field1 is not an identity field, so it does NOT autonumber. Unfortunately I can't change the table. Existing inserts are made using code to increment and all involve looping/cursors. Something like SELECT MAX(field1) + 1
So, is there anyway to do this insert without looping/cursor? This field means nothing to me, but there are already 500,000+ records using their silly numbering scheme, so I must respect that.
This is simplified (ReceiptNumber is the field I want to insert unique), but:
SET XACT_ABORT ON
Begin Transaction TransMain
Declare #nvErrMsg nvarchar(4000)
--Insert inventory receipts
Insert Into Avanti_InventoryReceipts (
ReceiptNumber , ItemNumber , ReceiptDate , OrderNumber , JobNumber , Supplier ,
LineNumber , MultiLineNumber , [Status] , QtyOrdered , QtyReceived , QtyToReceive ,
QtyBackOrdered , Cost , Wholesale , LastCost , QtyToInvoice , QtyUsed ,
ReferenceNumber , [Description] , SupplierType , Processed , DateExpected , DateReceived ,
AccountNumber , Reference2 , EmployeeCode , ExtraCode , Location , RollNumber ,
QtyIssues , Notes , NumPackages , BundleSize , ConsignmentUnitPrice , RecFromProduction ,
QtyCommitted )
SELECT ( SELECT MAX(ReceiptNumber) + 1 FROM Avanti_inventoryReceipts ) , CR.ItemNumber , Convert(char(8), GETDATE(), 112) , PONum , 'FL-INV' , PH.POVendor ,
0 , 0 , 'O' , CR.QtyOrdered , QtyReceivedToday , QtyReceivedToday ,
Case #closePO
When 'N' Then Case When ( QtyOrdered - QtyReceivedToday ) < 0 Then 0 Else ( QtyOrdered - QtyReceivedToday) End
When 'Y' Then 0
Else 0 End
, PD.TransCost * QtyReceivedToday , IH.PriceWholeSale , IH.CostLast , QtyReceivedToday , 0 ,
'' , PODetailDescription , '' , '' , '' , Convert(char(8), GETDATE(), 112) ,
'' , '' , #employeeCode , '' , 'F L E X O' , '' ,
0 , 'Flexo Materials' , 0 , 0 , 0 , '' , 0
FROM FI_CurrentReceiptData CR
LEFT JOIN Avanti_PODetails PD ON CR.PONum = PD.PONumber
LEFT JOIN Avanti_POHeader PH ON CR.PONum = PH.PONumber
LEFT JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber
IF ##ERROR <> 0
Begin
Select #nvErrMsg = 'Error entering into [InventoryReceipts] -' + [description]
From master..sysmessages
Where [error] = ##ERROR
RAISERROR ( #nvErrMsg , 16, 1 )
Goto Err_
End
Commit Transaction TransMain
Goto Exit_
Err_:
Rollback Transaction TransMain
Exit_:
SET XACT_ABORT OFF
You could do this:
insert into mytable (field1, field2, ...)
values (( SELECT MAX(field1) + 1 from mytable), 'value2', ...);
Why not looping? It should be quite efficient.
Since you already have a UNIQUE constraint on the field, you can:
Simply try to insert MAX(field1) + 1. Since there is index on UNIQUE field, MAX is fast.
If its passes, great you are done.
If it fails (which will typically be manifested as an exception in your client code), just try again until you succeed.
Most of the time, the INSERT will succeed right away. In rare instances where a concurrent user tries to insert the same value, you'll handle that gracefully by trying the "next" value.
I added an autonumber starting from 0 in client code and passed that in. Now I'm adding that value to the max receiptnumber to get a unique one. Also, I realized I already had an identity column in FI_CurrentReceiptData, but I didn't want to use that one because it won't start at 0 for each receipt set, and reseeding the identity each time seems like a waste of processor time.