ERROR CODE 1241 :OPERAND SHOULD CONTAIN 1 COLUMN(S) - select

My goal is to retrieve all accounts where the balance is greater than zero.
I have two table the tblloancontract and the tblloanpayment.
tblloancontract has two columns: accnum, and idmember.
tblloanpayment has: idpayment, balance, and accnum (a foreign key from tblloancontract).
Below is the MYSQL code I have written so far:
SELECT * FROM tblloanpayment WHERE accnum IN
(SELECT MAX(idpayment), tblloanpayment.accnum, MIN(tblloanpayment.balance)
FROM tblloanpayment JOIN tblloancontract ON tblloanpayment.accnum=tblloancontract.accnum
GROUP BY idmember) AND balance > 0;

Don't you just want all accounts where the lowest balance is greater than 0? In that case, why do you need the tblloancontract table at all?
SELECT tlp.accnum, MIN(tlp.balance)
FROM tblloanpayment tlp
GROUP BY tlp.accnum
HAVING MIN(tlp.balance) > 0;
That's not really a very good way to store loan information. The "contract" table should have the initial balance and the current balance, and the "payment" table should have the payment amounts.

Related

Unexpected Results From Postgresql Query

I am trying to find a way to create a table where it shows each customer profile (71 in total) their top item bought per time frame (10 in total), what that item is, and the time frame that was most popular. Whenever I run this query it shows the top items for a time frame but it shows all the customers as null. I also need a way to display the customer name which is also accessed through the id_table. I'm lost so any direction would be greatly appreciated! I only have read permissions on this DB.
select distinct id_table.name as product_name, pb.recruitment_round, count(pb.purchased), st.cust_dbf_id as cust_profile
from product_bought pb
join id_table
on id_table.dbf_id = pb.dbf_id
left join shopper_table st
on st.cust_dbf_id = id_table.dbf_id
where pb.date >= '2022-01-01'
and pb.date <= '2022-01-05'
and pb.shopping_time = 4
group by id_table."name", pb.recruitment_round, pb.cust_dbf_id
order by count(pb.purchased) desc, pb.recruitment_round
limit 1;
Expected: a return of st.cust_dbf_id.
Received: Null values

TSQL select and join issue

I have two tables, EMPL which is a historical employee table to track changes in an employee's tax rate and PAYROLL which is also a historical table filled with employee pay over a number of periods.
FROM EMPL, based upon the EMPL.effect_pd <= PAYROLL.payroll_pd, only one record should be joined from EMPL to PAYROLL.
Below are the two tables, query and result set. However, I only want 1 record for each employee per pay period, which matches the relevant employee record based upon the payroll_pd and effect_pd.
(Click image to enlarge)
first of all - welcome!
You wrote "...FROM EMPL, based upon the EMPL.effect_pd <= PAYROLL.payroll_pd ..." but you start your SQL with PAYROLL and not with EMPL.
Pls test this statement first:
SELECT
E.rec_id
,E.empl_id
,E.empl_name
,E.tax_rate
,E.effect_pd
,P.rec_id
,P.payroll_pd
,P.empl_id
,P.pd_pay
FROM
empl AS E
LEFT OUTER JOIN
payroll AS P
ON E.empl_id = P.empl_id
AND E.effect_pd < P.payroll_pd
After that you get 7 records witch are uniqe.
i think, thats it.
Best regards
After 3 days of messing around with the code, I finally arrived at the solution which is:
SELECT * FROM PAYROLL p
LEFT JOIN EMPL e on p.empl_id = e.empl_id
WHERE e.rec_id = ( SELECT TOP 1 c.rec_id
FROM EMPL c
WHERE c.empl_id = p.empl_id
AND p.payroll_pd >= c.effect_pd
ORDER BY c.effect_pd DESC );

Preventing aggregated rows of total invoice volumes when using GROUPBY to find percentage of paid invoices

I'm trying to determine the total amount of partial payment instances made to a single invoice total, but when I do the INNER JOIN to calculate the partial payments, T-SQL automatically aggregates each invoice amount for each partial payment made towards it, skewing the invoice totals. It's not throwing any errors, but I've tried everything I can think of, so if anyone has any helpful advice on how to approach this, it'd be much appreciated!
DECLARE #StartYear INT
SET #StartYear = '2014'
DECLARE #EndYear INT
SET #EndYear = '2018'
SELECT
COUNT(i.InvoiceKey) AS InvoiceKey,
ISNULL(YEAR(p.TransPostDate), #StartYear) AS PaymentYear,
SUM(i.Amt) AS InvoiceAmount,
SUM(p.Amt) AS PartialPaymentsTotalsAmount
FROM .[Invoices] i
INNER JOIN [Payments] p ON i.InvoiceKey = p.InvoiceKey
WHERE i.ClientKey = '518'
AND p.InvClientKey = '518'
AND i.CloseDate IS NULL
AND (p.TransPostDate IS NOT NULL OR ((YEAR(p.TransPostDate) * 100)) BETWEEN ((#StartYear * 100)) AND ((#EndYear * 100)) )
GROUP BY i.InvoiceKey, YEAR(p.TransPostDate)
ORDER BY YEAR(p.TransPostDate) ASC;
If I understand correctly, you sum of the number of payments made that were less than the invoice total. You can use a CASE statement within a COUNT to achieve this. I also simplified your code a bit:
declare #StartYear int = '2014';
declare #EndYear int = '2018';
select count(i.InvoiceKey) as [Number of Payments made on Invoice]
-- this will never by null because of the WHERE clause
,year(p.TransPostDate) as PaymentYear
-- I assume multiple payments to one invoice, so don't want to sum here.
-- All values are the same, just take the MAX. MIN would work too.
,max(i.Amt) as [Invoice Amount]
,sum(p.Amt) as [Total Payment Made]
-- count of partial payments
,count(case when p.Amt < i.Amt then i.InvoiceKey end) [Number of partial payments made]
-- sum of partial payments
,sum(case when p.Amt < i.Amt then p.Amt end) [Sum of partial payments made]
from.[Invoices] i
inner join [Payments] p
on i.InvoiceKey = p.InvoiceKey
where i.ClientKey = '518'
and p.InvClientKey = '518'
and i.CloseDate is null
-- if this is not true, then by definition p.TransPostDate is not null so
-- you don't need to specify "p.TransPostDate IS NOT NULL".
-- There is no need to multiply by 100
and year(p.TransPostDate) between #StartYear and #EndYear
group by i.InvoiceKey
,year(p.TransPostDate)
order by year(p.TransPostDate) asc;

Indicate more than one record with matching fields

How can I indicate multiple records with the same Invoice number, but a different Sales Person ID? Our commissions can be split into multiple Salespeople, so there can be two different Salespeople per an invoice.
For example:
Grouped by: Sales Person ID (No Changing this option)
These records are in the Group Footer.
Sales Person ID: Invoice: Invoice Amt: Commissions: (Indicator)
4433 R100 20,000 3,025 * More than one record on the same invoice with a different sales person
4450 R096 1,987 320
4599 R100 20,000 3,025 * More than one record on the same invoice with a different sales person
4615 R148 560 75
4777 R122 2,574 356
If your report has less than 1000 invoices, you may try something like this.
This will return true when a second ocurrence of the invoice shows up. Then you can make something like set the row background do red.
Global NumberVar Array invoices;
numbervar nextIndex := count(invoices) + 1;
if nextIndex <= 1000 and not ({Result.InvoiceNumber} in invoices) then (
redim invoices [nextIndex];
invoices[nextIndex] := {Result.InvoiceNumber};
true;
)
else false;
If you want to detect the first occurrence, you will need something more sophisticated.
I think a SQL Expression Field would be a good way to achieve the result you want. You already have an InvoiceNo in each row of data. You just need a SQL Expression Field that uses that INvoiceNo to execute a query to count the number of salespersons who get a commission.
Something along the lines of:
(
Select Count(Sales_Person_Id)
From [Table]
Where [Table].InvoiceNo = InvoiceNo
)
This will return an integer value that represents the number of salespersons who are associated with one invoice. You can either drop the SQL Expression Field in your Indicator column, or write some other formula to do something special.

T-SQL Query to process data in batches without breaking groups

I am using SQL 2008 and trying to process the data I have in a table in batches, however, there is a catch. The data is broken into groups and, as I do my processing, I have to make sure that a group will always be contained within a batch or, in other words, that the group will never be split across different batches. It's assumed that the batch size will always be much larger than the group size. Here is the setup to illustrate what I mean (the code is using Jeff Moden's data generation logic: http://www.sqlservercentral.com/articles/Data+Generation/87901)
DECLARE #NumberOfRows INT = 1000,
#StartValue INT = 1,
#EndValue INT = 500,
#Range INT
SET #Range = #EndValue - #StartValue + 1
IF OBJECT_ID('tempdb..#SomeTestTable','U') IS NOT NULL
DROP TABLE #SomeTestTable;
SELECT TOP (#NumberOfRows)
GroupID = ABS(CHECKSUM(NEWID())) % #Range + #StartValue
INTO #SomeTestTable
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2
This will create a table with about 435 groups of records containing between 1 and 7 records in each. Now, let's say I want to process these records in batches of 100 records per batch. How can I make sure that my GroupID's don't get split between different batches? I am fine if each batch is not exactly 100 records, it could be a little more or a little less.
I appreciate any suggestions!
This will result in slightly smaller batches than 100 entries, it'll remove all groups that aren't entirely in the selection;
WITH cte AS (SELECT TOP 100 * FROM (
SELECT GroupID, ROW_NUMBER() OVER (PARTITION BY GroupID ORDER BY GroupID) r
FROM #SomeTestTable) a
ORDER BY GroupID, r DESC)
SELECT c1.GroupID FROM cte c1
JOIN cte c2
ON c1.GroupID = c2.GroupID
AND c2.r = 1
It'll select the groups with the lowest GroupID's, limited to 100 entries into a common table expression along with the row number, then it'll use the row number to throw away any groups that aren't entirely in the selection (row number 1 needs to be in the selection for the group to be, since the row number is ordered descending before cutting with TOP).