Adding zero values to report - sql

Ok This is a good question I think.
At the moment I have a report showing amount of tickets per machine and how much each machine made in ticket sales.
Some machines sell Zero tickets but they are not includded in my report.
Now i want to include them.
there is a full list of all machines in machconfig table which I could compare to the ticketssold table which also has a field corresponding to the machine that sold it.
So I guess I could find all of the machines that havent sold any tickets by looking for machine id's (MCHterminalid) that dont appear in the ticketssold table (TKtermid column)
here is the code I've got so far..
SELECT TKtermID,
MCHlocation,
Count (TKvouchernum) AS Totaltickets,
Cast(Sum(TKcomission) AS FLOAT) / 100 AS Total_Comission
FROM ticketssold(NOLOCK)
INNER JOIN machconfig (NOLOCK)
ON MCHterminalID = TKtermID
WHERE cfglocationcountry = 'UK'
AND dateadded BETWEEN Getdate() - 100 AND Getdate()
GROUP BY vstermID,
cfglocation
ORDER BY Total_comission DESC

Change the inner join between ticketssold and machconfig to a right outer join to get all machines, regardless of a match in the tickets sold table. The count of TKVouchernum will return the zeros for you:
SELECT TKtermID,
MCHlocation,
Count (TKvouchernum) AS Totaltickets,
Cast(Sum(TKcomission) AS FLOAT) / 100 AS Total_Comission
FROM ticketssold(NOLOCK)
RIGHT OUTER JOIN machconfig (NOLOCK)
ON MCHterminalID = TKtermID
WHERE cfglocationcountry = 'UK'
AND dateadded BETWEEN DateAdd(DAY, -100, GetDate()) AND Getdate()
GROUP BY vstermID,
cfglocation
ORDER BY Total_comission DESC

OCD Version not totally proofed (also killing me that table names are not included before the fields). Use the outer join in combination with COALESCE
SELECT
TKTermID TicketTerminalId,
MchLocation MachineLocation,
COALESCE(COUNT(TKVoucherNum),0) TotalTickets,
COALESCE(CAST(SUM(TKComission) AS float),0) / 100 TotalComission
FROM
MachConfig (NOLOCK)
LEFT JOIN
TicketsSold (NOLOCK)
ON
TKtermID = MCHterminalID
WHERE
CfgLocationCountry = 'UK'
AND
DateAdded BETWEEN DATEADD(DAY, -100, GETDATE()) AND GETDATE()
GROUP BY
VSTermID,
CfgLocation
ORDER BY
COALESCE(CAST(SUM(TKComission) AS float),0) / 100 DESC; --Do this in reporting!

Do not use inner joins because they will eliminate rows. I start my joins with the table that has all the data. In this case machconfig and then do a left outer join to the table with the problematic data ticketssold.
You may also want to think about doing your grouping on the report side for flexibility.

Finally got it working the way I want.. Here is the proper code:
SELECT MCHTerminalID, MCHLocation, ISNULL(CONVERT(varchar(16), batch.LastBatchIn, 103),
'Did not batch in') AS LastBatchIn,
ISNULL(COUNT(Ticket.VoucherNum), 0) AS TotalVouchers,
ISNULL(SUM(Ticket.Sale), 0) AS TotalGrossAmount, ISNULL(SUM(Ticket.Refund),0) AS TotalRefundAmount, ISNULL(SUM(Ticket.Comission),0) AS TotalComission
FROM termConfig AS config WITH (NOLOCK)
LEFT OUTER JOIN
(SELECT bsTerminalID, MAX(bsDateTime) AS LastBatchIn
FROM batchSummary WITH (NOLOCK)
WHERE bsDateTime BETWEEN getdate()-50 AND getdate()
GROUP BY bsTerminalID
)
AS batch
ON config.MCHTerminalID = batch.bsTerminalID
LEFT OUTER JOIN
(SELECT DISTINCT TKTermID,
TKVoucherNum AS VoucherNum,
CAST(TKGrossTotal AS float)/100 AS Sale,
CAST(TKRefundAmount AS float)/100 AS Refund,
CAST(TKComission AS float)/100 AS Comission
FROM TicketVouchers WITH (NOLOCK)
WHERE dateAdded BETWEEN getdate()-50 AND getdate()
)
AS Ticket
ON
config.MCHTerminalID = Ticket.TKTermID
WHERE
config.MCHLocationCountry = 'uk'
AND config.MCHProductionTerminal = 'Y'
GROUP BY config.MCHTerminalID, config.MCHLocation, LastBatchIn
ORDER BY TotalComission desc

You could UNION the 'zero' rows to your original e.g.
<original query here>
...
UNION
SELECT MCHterminalID,
MCHlocation,
0 AS Totaltickets,
0 AS Total_Comission
FROM machconfig
WHERE NOT EXISTS (
SELECT *
FROM ticketssold
WHERE MCHterminalID = TKtermID
)
(Review for hints).

Related

daily incremental results on table where transaction date <= #Date parameter

specifically looking for General Leger results. This means that I can't sum up transactions for specfic dates, or cant run Between date.
to get the results for say, today I would need to query the table for all transactions <= #Today.
That said, i am tasked with running this for every single day in 2020 thus far. is there a method to do this where i dont have to manually run for each day myself?
Query example:
glo.GLValue
, Sum(UnitCR) AS 'Credit'
, Sum(UnitDR) AS 'Debit'
, sum(FirmCR) AS 'FirmCredit'
, sum(FirmDR) AS 'FirmDebit'
FROM glacct ga
inner join gldetail gd on gd.glacct = ga.AcctIndex
inner join glnatural gn on ga.glnatural = gn.GLNaturalID
inner join glunit glu on ga.glunit = glu.GLUnitID
inner join gloffice glo on ga.GLOffice = glo.GLOfficeID
WHERE gn.GLNat IN ('11001','11002','11003','11005','11007','11011','11016','11019','11020','11021','11022','11024','11025','11026','11027','11032','11033',
'11034','11035','11036','11037','11040','11041','11042','11043','11044','11050','11051','11052','11053','11190','11199','11201','11202','11203','11204',
'11205','11206','11207','11301','11603','11700','11705','11801','11802','11803','11804','11806','11807','11808','11809','11901')--,'22001')
AND gd.PostDate <= #Yesterday
GROUP BY
glo.GLValue
Create a sub-table that give the sums for each PostDate and GLValue similar to above but also grouped on PostDate, then join that to your select above, e.g.
inner join gloffice glo on ga.GLOffice = glo.GLOfficeID
inner join ( ... new grouped select here ...) gs on gs.GLValue = glo.GlValue and gs.PostDate < gd.PostDate
Now you should be able to sum the gs values:
, Sum(gs.Credit) as Credit
, Sum(gs.Debit) as Debit
etc.

How could I join these queries together?

I have 2 queries. One includes a subquery and the other is a pretty basic query. I can't figure out how to combine them to return a table with name, workdate, minutes_inactive, and hoursworked.
I have the code below for what I have tried. The simple query is lines 1,2, and the last 5 lines. I also added a join clause (join punchclock p on p.servrepID = l.repid) to it.
Both these queries ran on their own so this is solely just the problem of combining them.
select
sr.sr_name as liaison, cast(date_created as date) workdate,
(count(date_created) * 4) as minutes_inactive,
(select
sr_name, cast(punchintime as date) as workdate,
round(sum(cast(datediff(minute,punchintime, punchouttime) as real) / 60), 2) as hoursworked,
count(*) as punches
from
(select
sr_name, punchintime = punchdatetime,
punchouttime = isnull((select top 1 pc2.punchdatetime
from punchclock pc2
where pc2.punchdatetime > pc.punchdatetime
and pc.servrepid = pc2.servrepid
and pc2.inout = 0
order by pc2.punchdatetime), getdate())
from
punchclock pc
join
servicereps sr on pc.servrepid = sr.servrepid
where
punchyear >= 2017 and pc.inout = 1
group by
sr_name, cast(punchintime as date)))
from
tbl_liga_popup_log l
join
servicereps sr on sr.servrepID = l.repid
join
punchclock p on p.servrepID = l.repid collate latin1_general_bin
group by
cast(l.date_created as date), sr.sr_name
I get this error:
Msg 102, Level 15, State 1, Line 19
Incorrect syntax near ')'
I keep getting this error but there are more errors if I adjust that part.
I don't know that we'll fix everything here, but there are a few issues with your query.
You have to alias your sub-query (technically a derived table, but whatever)
You have two froms in your outer query.
You have to join to the derived table.
Here's an crude example:
select
<some stuff>
from
(select col1 from table1) t1
inner join t2
on t1.col1 = t2.col2
The large error here is that you are placing queries in the select section (before the from). You can only do this if the query returns a single value. Else, you have to put your query in a parenthesis (you have done this) in the from section, give it an alias, and join it accordingly.
You also seem to be using group bys that are not needed anywhere. I can't see aggregation functions like sum().
My best bet is that you are looking for the following query:
select
sr_name as liaison
,cast(date_created as date) workdate
,count(distinct date_created) * 4 as minutes_inactive
,cast(punchintime as date) as workdate
,round(sum(cast(datediff(minute,punchintime,isnull(pc2_query.punchouttime,getdate())) as real) / 60), 2) as hoursworked
,count(*) as punches
from
punchclock pc
inner join servicereps sr on pc.servrepid = sr.servrepid
cross apply
(
select top 1 pc2.punchdatetime as punchouttime
from punchclock pc2
where pc2.punchdatetime > pc.punchdatetime
and pc.servrepid = pc2.servrepid
and pc2.inout = 0
order by pc2.punchdatetime
)q1
inner join tbl_liga_popup_log l on sr.servrepID = l.repid
where punchyear >= 2017 and pc.inout = 1

SQL add Sum to existing query (Cannot perform an aggregate function on an expression containing an aggregate or a subquery.)

I have a existing working SQL query I would like to now GroupBy but am getting the error: Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Explanation of my scenario:
My main table (dbo.DataLog) contains 3 columns, TimestampUTC, MeterTagId, Data.
Data typically comes in at 15 minute intervals and I have many meters (MeterTagId) for each
TimestampUTC. The Data column is a float and this is a totalised value. i.e. to get the actual value for a meter period I need to subtract the last value from the current one. Before now I have successfully been querying individual meters but now I am trying to group by time and show a sum/total of all meters for that time.
Original working non summed query:
SELECT
l.TimestampUTC
-- Get this value minus the last value
,(SELECT (l.[Data] -
( SELECT TOP 1 l2.Data
FROM [DataLog] l2
WHERE l2.MeterTagId = l.MeterTagId
AND l2.TimestampUTC < l.TimestampUTC
ORDER BY l2.TimestampUTC DESC)
)
) AS Actual_Value
FROM [dbo].[DataLog] l
INNER JOIN [dbo].MeterTags t on t.MeterTagId = l.MeterTagId
INNER JOIN [dbo].Meters m on m.MeterId = t.MeterId
INNER JOIN [dbo].GroupsMeters gm on gm.MeterId = m.MeterId
INNER JOIN [dbo].Groups g on g.GroupId = gm.GroupId
LEFT OUTER JOIN dbo.Units u on u.UnitId = t.UnitId
WHERE (#MeterId is null OR M.MeterId in (#MeterId))
AND (#MeterTagId is null OR t.MeterTagId in (#MeterTagId))
AND (#StartDate is null OR l.TimestampUTC >= #StartDate)
AND (#EndDate is null OR l.TimestampUTC <= #EndDate)
AND (#GroupId is null OR g.GroupId in (#GroupId))
.
My attempt to to get the summary:
SELECT
l.TimestampUTC
-- Get this value minus the last value
, (SELECT SUM(l.[Data] -
( SELECT TOP 1 l2.Data
FROM [DataLog] l2
WHERE l2.MeterTagId = l.MeterTagId
AND l2.TimestampUTC < l.TimestampUTC
ORDER BY l2.TimestampUTC DESC)
)
)AS Actual_Value
FROM [dbo].[DataLog] l
INNER JOIN [dbo].MeterTags t on t.MeterTagId = l.MeterTagId
INNER JOIN [dbo].Meters m on m.MeterId = t.MeterId
INNER JOIN [dbo].GroupsMeters gm on gm.MeterId = m.MeterId
INNER JOIN [dbo].Groups g on g.GroupId = gm.GroupId
LEFT OUTER JOIN dbo.Units u on u.UnitId = t.UnitId
WHERE (#MeterId is null OR M.MeterId in (#MeterId))
AND (#MeterTagId is null OR t.MeterTagId in (#MeterTagId))
AND (#StartDate is null OR l.TimestampUTC >= #StartDate)
AND (#EndDate is null OR l.TimestampUTC <= #EndDate)
AND (#GroupId is null OR g.GroupId in (#GroupId))
AND t.Name ='Real Energy Net'
GROUP BY l.TimestampUTC
I have read other posts on here but can't get my head around the logic required, I imagine/hope this is something sql dev's come across regularly? Thanks!
OK, I worked it out, it's simple really. Hopefully this explanation helps someone else with the same issue in the future.
SELECT
myTable.TimestampUTC
, SUM(myTable.Actual_Value) as [Actual Value]
FROM
(
--My original query
) AS myTable
GROUP BY myTable.TimestampUTC

Compare values from one table with the results from a query?

First, I will explain the what is being captured. User's have a member level associated with their accounts (Bronze, Gold, Diamond, etc). A nightly job needs to run to calculate the orders from today a year back. If the order total for a given user goes over or under a certain amount their level is upgraded or downgraded. The table where the level information is stored will not change much, but the minimum and maximum amount thresholds may over time. This is what the table looks like:
CREATE TABLE [dbo].[MemberAdvantageLevels] (
[Id] int NOT NULL IDENTITY(1,1) ,
[Name] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[MinAmount] int NOT NULL ,
[MaxAmount] int NOT NULL ,
CONSTRAINT [PK__MemberAd__3214EC070D9DF1C7] PRIMARY KEY ([Id])
)
ON [PRIMARY]
GO
I wrote a query that will group the orders by user for the year to date. The query includes their current member level.
SELECT
Sum(dbo.tbh_Orders.SubTotal) AS OrderTotals,
Count(dbo.UserProfile.UserId) AS UserOrders,
dbo.UserProfile.UserId,
dbo.UserProfile.UserName,
dbo.UserProfile.Email,
dbo.MemberAdvantageLevels.Name,
dbo.MemberAdvantageLevels.MinAmount,
dbo.MemberAdvantageLevels.MaxAmount,
dbo.UserMemberAdvantageLevels.LevelAchievmentDate,
dbo.UserMemberAdvantageLevels.LevelAchiementAmount,
dbo.UserMemberAdvantageLevels.IsCurrent as IsCurrentLevel,
dbo.MemberAdvantageLevels.Id as MemberLevelId,
FROM
dbo.tbh_Orders
INNER JOIN dbo.tbh_OrderStatuses ON dbo.tbh_Orders.StatusID = dbo.tbh_OrderStatuses.OrderStatusID
INNER JOIN dbo.UserProfile ON dbo.tbh_Orders.CustomerID = dbo.UserProfile.UserId
INNER JOIN dbo.UserMemberAdvantageLevels ON dbo.UserProfile.UserId = dbo.UserMemberAdvantageLevels.UserId
INNER JOIN dbo.MemberAdvantageLevels ON dbo.UserMemberAdvantageLevels.MemberAdvantageLevelId = dbo.MemberAdvantageLevels.Id
WHERE
dbo.tbh_OrderStatuses.OrderStatusID = 4 AND
(dbo.tbh_Orders.AddedDate BETWEEN dateadd(year,-1,getdate()) AND GETDATE()) and IsCurrent = 1
GROUP BY
dbo.UserProfile.UserId,
dbo.UserProfile.UserName,
dbo.UserProfile.Email,
dbo.MemberAdvantageLevels.Name,
dbo.MemberAdvantageLevels.MinAmount,
dbo.MemberAdvantageLevels.MaxAmount,
dbo.UserMemberAdvantageLevels.LevelAchievmentDate,
dbo.UserMemberAdvantageLevels.LevelAchiementAmount,
dbo.UserMemberAdvantageLevels.IsCurrent,
dbo.MemberAdvantageLevels.Id
So, I need to check the OrdersTotal and if it exceeds the current level threshold, I then need to find the Level that fits their current order total and create a new record with their new level.
So for example, lets say jon#doe.com currently is at bronze. The MinAmount for bronze is 0 and the MaxAmount is 999. Currently his Orders for the year are at $2500. I need to find the level that $2500 fits within and upgrade his account. I also need to check their LevelAchievmentDate and if it is outside of the current year we may need to demote the user if there has been no activity.
I was thinking I could create a temp table that holds the results of all levels and then somehow create a CASE statement in the query above to determine the new level. I don't know if that is possible. Or, is it better to iterate over my order results and perform additional queries? If I use the iteration pattern I know i can use the When statement to iterate over the rows.
Update
I updated my Query A bit and so far came up with this, but I may need more information than just the ID from the SubQuery
Select * into #memLevels from MemberAdvantageLevels
SELECT
Sum(dbo.tbh_Orders.SubTotal) AS OrderTotals,
Count(dbo.AZProfile.UserId) AS UserOrders,
dbo.AZProfile.UserId,
dbo.AZProfile.UserName,
dbo.AZProfile.Email,
dbo.MemberAdvantageLevels.Name,
dbo.MemberAdvantageLevels.MinAmount,
dbo.MemberAdvantageLevels.MaxAmount,
dbo.UserMemberAdvantageLevels.LevelAchievmentDate,
dbo.UserMemberAdvantageLevels.LevelAchiementAmount,
dbo.UserMemberAdvantageLevels.IsCurrent as IsCurrentLevel,
dbo.MemberAdvantageLevels.Id as MemberLevelId,
(Select Id from #memLevels where Sum(dbo.tbh_Orders.SubTotal) >= #memLevels.MinAmount and Sum(dbo.tbh_Orders.SubTotal) <= #memLevels.MaxAmount) as NewLevelId
FROM
dbo.tbh_Orders
INNER JOIN dbo.tbh_OrderStatuses ON dbo.tbh_Orders.StatusID = dbo.tbh_OrderStatuses.OrderStatusID
INNER JOIN dbo.AZProfile ON dbo.tbh_Orders.CustomerID = dbo.AZProfile.UserId
INNER JOIN dbo.UserMemberAdvantageLevels ON dbo.AZProfile.UserId = dbo.UserMemberAdvantageLevels.UserId
INNER JOIN dbo.MemberAdvantageLevels ON dbo.UserMemberAdvantageLevels.MemberAdvantageLevelId = dbo.MemberAdvantageLevels.Id
WHERE
dbo.tbh_OrderStatuses.OrderStatusID = 4 AND
(dbo.tbh_Orders.AddedDate BETWEEN dateadd(year,-1,getdate()) AND GETDATE()) and IsCurrent = 1
GROUP BY
dbo.AZProfile.UserId,
dbo.AZProfile.UserName,
dbo.AzProfile.Email,
dbo.MemberAdvantageLevels.Name,
dbo.MemberAdvantageLevels.MinAmount,
dbo.MemberAdvantageLevels.MaxAmount,
dbo.UserMemberAdvantageLevels.LevelAchievmentDate,
dbo.UserMemberAdvantageLevels.LevelAchiementAmount,
dbo.UserMemberAdvantageLevels.IsCurrent,
dbo.MemberAdvantageLevels.Id
This hasn't been syntax checked or tested but should handle the inserts and updates you describe. The insert can be done as single statement using a derived/virtual table which contains the orders group by caluclation. Note that both the insert and update statement be done within the same transaction to ensure no two records for the same user can end up with IsCurrent = 1
INSERT UserMemberAdvantageLevels (UserId, MemberAdvantageLevelId, IsCurrent,
LevelAchiementAmount, LevelAchievmentDate)
SELECT t.UserId, mal.Id, 1, t.OrderTotals, GETDATE()
FROM
(SELECT ulp.UserId, SUM(ord.SubTotal) OrderTotals, COUNT(ulp.UserId) UserOrders
FROM UserLevelProfile ulp
INNER JOIN tbh_Orders ord ON (ord.CustomerId = ulp.UserId)
WHERE ord.StatusID = 4
AND ord.AddedDate BETWEEN DATEADD(year,-1,GETDATE()) AND GETDATE()
GROUP BY ulp.UserId) AS t
INNER JOIN MemberAdvantageLevels mal
ON (t.OrderTotals BETWEEN mal.MinAmount AND mal.MaxAmount)
-- Left join needed on next line in case user doesn't currently have a level
LEFT JOIN UserMemberAdvantageLevels umal ON (umal.UserId = t.UserId)
WHERE umal.MemberAdvantageLevelId IS NULL -- First time user has been awarded a level
OR (mal.Id <> umal.MemberAdvantageLevelId -- Level has changed
AND (t.OrderTotals > umal.LevelAchiementAmount -- Acheivement has increased (promotion)
OR t.UserOrders = 0)) -- No. of orders placed is zero (de-motion)
/* Reset IsCurrent flag where new record has been added */
UPDATE UserMemberAdvantageLevels
SET umal1.IsCurrent=0
FROM UserMemberAdvantageLevels umal1
INNER JOIN UserMemberAdvantageLevels umal2 On (umal2.UserId = umal1.UserId)
WHERE umal1.IsCurrent = 1
AND umal2.IsCurrent = 2
AND umal1.LevelAchievmentDate < umal2.LevelAchievmentDate)
One approach:
with cte as
(SELECT Sum(o.SubTotal) AS OrderTotals,
Count(p.UserId) AS UserOrders,
p.UserId,
p.UserName,
p.Email,
l.Name,
l.MinAmount,
l.MaxAmount,
ul.LevelAchievmentDate,
ul.LevelAchiementAmount,
ul.IsCurrent as IsCurrentLevel,
l.Id as MemberLevelId
FROM dbo.tbh_Orders o
INNER JOIN dbo.UserProfile p ON o.CustomerID = p.UserId
INNER JOIN dbo.UserMemberAdvantageLevels ul ON p.UserId = ul.UserId
INNER JOIN dbo.MemberAdvantageLevels l ON ul.MemberAdvantageLevelId = l.Id
WHERE o.StatusID = 4 AND
o.AddedDate BETWEEN dateadd(year,-1,getdate()) AND GETDATE() and
IsCurrent = 1
GROUP BY
p.UserId, p.UserName, p.Email, l.Name, l.MinAmount, l.MaxAmount,
ul.LevelAchievmentDate, ul.LevelAchiementAmount, ul.IsCurrent, l.Id)
select cte.*, ml.*
from cte
join #memLevels ml
on cte.OrderTotals >= ml.MinAmount and cte.OrderTotals <= ml.MaxAmount

SQL UNION query not working

here is my current queries:
1
SELECT FilteredInvoice.accountidname,
FilteredInvoice.createdon,
FilteredInvoice.createdon AS sort_date,
FilteredInvoice.duedate,
FilteredInvoice.invoicenumber,
FilteredInvoice.statecodename,
FilteredInvoice.totalamount_base,
CONVERT(datetime, NULL) AS mag_paymentdate,
0 AS mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
JOIN FilteredInvoice ON FilteredInvoice.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice.statecodename <> 'Canceled')
2
SELECT FilteredInvoice_1.accountidname,
FilteredInvoice_1.createdon,
FilteredInvoice_1.createdon AS sort_date,
FilteredInvoice_1.duedate,
FilteredInvoice_1.invoicenumber,
FilteredInvoice_1.statecodename,
FilteredInvoice_1.totalamount_base,
FilteredMag_Payment.mag_paymentdate,
FilteredMag_Payment.mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
LEFT JOIN FilteredInvoice AS FilteredInvoice_1 ON FilteredInvoice_1.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice_1.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice_1.statecodename <> 'Canceled')
These alone do exactly what i am wanting them to but as soon as i try and join them using a "UNION" or "Sub-query" the second query always breaks and displays the wrong information.
Am I just being blond not being able to work this out or am I actually doing something wrong.
All help is appreciated.
Many thanks Simon.
EDIT:
What I mean by "Wrong information" is that the 2nd query is returning all values rather then following the CRMAF_ prefix and returning only values from the account it is run on.
It's hard to guess what do you mean by "wrong information" but I believe you want UNION ALL rather than UNION.
UNION removes duplicates so the records from the second query won't be returned if they were previously returned by the first query. In addition, the possible duplicates within one query will be eliminated too.
The number of records in a UNION can be less than the total count of records in two queries.
If you just want to concatenate two recordsets, use UNION ALL:
SELECT FilteredInvoice.accountidname,
FilteredInvoice.createdon,
FilteredInvoice.createdon AS sort_date,
FilteredInvoice.duedate,
FilteredInvoice.invoicenumber,
FilteredInvoice.statecodename,
FilteredInvoice.totalamount_base,
CONVERT(datetime, NULL) AS mag_paymentdate,
0 AS mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
JOIN FilteredInvoice ON FilteredInvoice.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice.statecodename <> 'Canceled')
UNION ALL
SELECT FilteredInvoice_1.accountidname,
FilteredInvoice_1.createdon,
FilteredInvoice_1.createdon AS sort_date,
FilteredInvoice_1.duedate,
FilteredInvoice_1.invoicenumber,
FilteredInvoice_1.statecodename,
FilteredInvoice_1.totalamount_base,
FilteredMag_Payment.mag_paymentdate,
FilteredMag_Payment.mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
LEFT JOIN FilteredInvoice AS FilteredInvoice_1 ON FilteredInvoice_1.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice_1.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice_1.statecodename <> 'Canceled')
It looks to me as though you should be able to get the same results as you would from the UNIONed query, with the following:
SELECT FilteredInvoice_1.accountidname,
FilteredInvoice_1.createdon,
FilteredInvoice_1.createdon AS sort_date,
FilteredInvoice_1.duedate,
FilteredInvoice_1.invoicenumber,
FilteredInvoice_1.statecodename,
FilteredInvoice_1.totalamount_base,
CASE PF.pay_flag
WHEN 0.0 THEN CONVERT(datetime, NULL)
ELSE FilteredMag_Payment.mag_paymentdate
END AS mag_paymentdate,
FilteredMag_Payment.mag_amount_base * PF.pay_flag AS mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
CROSS JOIN (SELECT 1.0 pay_flag UNION SELECT 0.0) AS PF
JOIN FilteredInvoice AS FilteredInvoice_1 ON FilteredInvoice_1.accountid = CRMAF_FilteredAccount.accountid
LEFT JOIN FilteredMag_Payment ON FilteredInvoice_1.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice_1.statecodename <> 'Canceled') AND
(PF.pay_flag = 0 OR FilteredMag_Payment.mag_invoiceid IS NOT NULL)
EDIT: LEFT JOIN FilteredMag_Payment
FURTHER EDIT: added final parenthesised OR condition to WHERE clause.