I am looking to find a way to write a CASE WHEN statement that returns a value if ANY of the items = a specific criteria. Here is a little background:
I have transactions that have several different assets on each transaction and those assets could all have different suppliers associated with them. I am aggregating the data to a transaction level and I am looking to flag the transactions where ANY asset on the transaction has a supplier that is the same as the customer on that transaction.
So if any supplier from all the assets on transaction X equals the customer on transaction X flag this deal
You can use exists. Without sample data and desired results, it is a little tricky to form the entire query, but something like this:
select t.*,
(case when exists (select 1 from suppliers s where t.customer = s.supplier)
then 1 else 0
end) as flag
from transactions t;
Related
I am trying to extract data from a GnuCash SQLite database. Relevant tables include accounts, transactions, and splits. Simplistically, accounts contain transactions which contain splits, and each split points back to an account.
The transactions need to be processed differently depending on whether each one does or does not include a particular kind of transaction fee—in this case whether or not the transaction contains a split linked to account 8190-000.
I've set up two queries, one that handles transactions with the transaction fee, and one that handles transactions without the transaction fee. The queries work, but they are awkward and wordy, and I'm sure there is a better way to do this. I did see not exists in this answer, but could not figure out how to make it work in this situation.
My current queries look like this:
-- Find all transactions containing a split with account code 8190-000
select tx_guid from transactions
inner join
(select tx_guid from
(splits inner join accounts on splits.account_guid = accounts.guid)
where accounts.code = "8190-000") fee_transactions
on fee_transactions.tx_guid = transactions.guid;
-- Find all transactions not containing a split with account code 8190-000
select guid from transactions
except
select tx_guid from transactions
inner join
(select tx_guid from
(splits inner join accounts on splits.account_guid = accounts.guid)
where accounts.code = "8190-000") fee_transactions
on fee_transactions.tx_guid = transactions.guid;
Given that I need to use these results in other queries, what is a simpler and more succinct way to obtain these lists of transactions?
You can use EXISTS for your 1st query like this:
SELECT t.*
FROM transactions t
WHERE EXISTS (
SELECT 1
FROM splits s INNER JOIN accounts a
ON s.account_guid = a.guid
WHERE a.code = '8190-000' AND ?.tx_guid = t.guid
);
Change ? to s or a, depending on which table contains the column tx_guid (splits or accounts), since it is not clear in your question.
Also, change to NOT EXISTS for your 2nd query.
I've got a bunch of tables, and I'm trying to pull various pieces of information from each of them. One of the pieces of information I need is if a customer is subscribed to the newsletter, but there is no linking data between the two tables apart from the email address. So, I'm trying to show a custom column, (e.g. SubscribedToNewsletter), which shows whether a customer's email address exists in the Subscriptions.Email values (i.e. True/False).
Customer
===============
Email
Subscriptions
===============
Email
I've tried things using CASE and EXISTS to try and forge a custom column based on whether a value exists in the column of the other table, but it's not producing any fruit.
SELECT
CASE WHEN Subscriptions.Email = Customer.Email THEN 'True' ELSE 'False' END
FROM Customer
INNER JOIN Subscriptions ON 1=1
WHERE EXISTS (SELECT 1 FROM Customer WHERE Subscriptions.Email = Customer.Email)
Use a correlated sub-query to count each customer's number of subscriptions:
select c.*,
case when (select count(*) from Subscriptions s
where s.Email = c.Email) > 0 then 'True'
else 'False'
end
from customers c
I have a program using SQL Server 2005 Express and I need some help looping through 2 tables to calculate inventory.
Table 1: stores all products with the inventory total upon setup
Table 2: stores the transactions against all products from table 1
How can I loop through all items in table 2 and subtract that amount from table 1 counts?
If I have my query like this then I get data for each product
SELECT
ii.ItemNum, ii.ItemName, ii.OzOnHand
FROM
dbo.InventoryItems ii
INNER JOIN
dbo.InventoryLog il ON ii.ItemNum = il.InvItemNum
WHERE
ii.active = 1
I need each occurrence from table 2 to be subtracted from table 1's total amount
This is an example of a join to an aggregated table (I think that is the best way to understand it):
SELECT ii.ItemNum, ii.ItemName, ii.OzOnHand, ii.OzOnHand - coalesce(il.cnt, 0)
FROM dbo.InventoryItems ii LEFT JOIN
(select il.InvItemNum, sum(OzRemoved) as cnt
from dbo.InventoryLog il
group by il.InvItemNum
) il
ON ii.ItemNum = il.InvItemNum
WHERE ii.active = 1;
The subquery groups everything in the log and counts the number of entries. If each entry could affect more than one item, then you would use something like sum(cnt) as cnt instead of count(*).
Then, the query uses a left outer join. This type of join ensures that all inventory items remain, even those with nothing in the log. Finally, the count is subtracted from what is available in set up. The coalesce() is to handle the situation where there are no matches in the log table. To avoid getting NULL, the NULL is turned into a 0.
OK, this is a second attempt to resolve my issue, for those who will read this a second time, i hope its clear enough to understand a problem.
I am developing a query for a report, the thing is that while retrieving data from database this report should populate some rows, which do not exist. For illustrating purpose lets say i have these tables :
Table 1 - Companies
Table 2 - Transactions.
Table 3 - Transaction types.
Important detail that most of the companies do not have transactions of all transaction types. Although the report logic requires to dysplay a company with all of them : "real" ones with real money values and other, not existed ones with just $0. The problem starts here because transaction types are combined in logical groups, so lets say if a company has only 1 real transaction of type_1, the report should contain "$0" records of other types associated with type_1, like type_2, type_3 and type_4. If company has transactions of type_1 and type_2, report should be populated with some other tran types from different transaction type group etc.
The problem here is that the environment where it should be executed must be a pure sql (being a java programmer i understand how easy is to query database, load data into array[][] and add missing transaction types) - but the query should be ran on UNIX inside plsql batch so it should be single (or joined) select.
Thanks in advance. Any help or ideas would be very appreciated!
It sounds like you just need some sort of outer join. I'm guessing at how your tables relate to each other but it appears that you want something like
SELECT c_typ_cross_join.company_name,
c_typ_cross_join.transaction_type,
nvl( sum( t.transaction_amount ), 0 ) total_amt
FROM (SELECT c.company_name,
typ.transaction_type
FROM companies c
FULL OUTER JOIN transaction_type typ) c_typ_cross_join
LEFT OUTER JOIN transactions t ON ( c_typ_cross_join.company_id = t.company_id
AND c_typ_cross_join.transaction_type = t.transaction_typ)
GROUP BY c_typ_cross_join.company_name,
c_typ_cross_join.transaction_type
This should produce one row for every company for every transaction type and the sum of the related transactions (or 0 if there are no transactions for the combination of companies and transaction types).
You could use two sub-queries one to find all transactions per company based on the existing types the company has, second to find the totals.
SELECT companies.id, all_transactions.transaction, COALESCE(sums.total_amount, 0)
FROM companies
JOIN (SELECT ct.companyid, t.transaction
FROM transactions ct
JOIN transactions t ON t.transactiontype = ct.transactiontype
GROUP BY ct.companyid, t.transaction) all_transactions ON all_transactions.companyid = companies.companyid
LEFT JOIN (SELECT ct.companyid, SUM(t.amount) as total_amount
FROM transactions ct
GROUP BY ct.companyid) sums ON sums.companyid = companies.companyid
Firstly, I'm rather new to SQL and I've run into a roadblock. I'm using the Mimer SQL system.
I have three tables: "Transactions", roughly equivalent with a receipt total, which I want to update with data from a selection and the tables "item", containing prices and "sale", containing number of items and item IDs for a given transaction, which I have to join in order to get the data to update Transaction with.
SELECT sale.T_ID, SUM(sale.quantity * item.price) as total
FROM sale
INNER JOIN item
ON sale.I_ID = item.I_ID
GROUP BY T_ID
Gives me the desired data selection with the transaction IDs and the sum total for that transaction:
T_ID Amount
1 100
2 150
etc...
I want to update the Transaction table, which contains columns "T_ID" and "Total". I want to match the T_IDs and update the Total with the data from the corresponding Amount in the selection. The query:
UPDATE transaction SET total = (
SELECT total FROM (
SELECT sale.T_ID, SUM(sale.quantity * item.price) as total
FROM sale
INNER JOIN item
ON sale.I_ID = item.I_ID
GROUP BY T_ID)
WHERE transaction.T_ID=T_ID);
I can sense that the above statement is faulty, but unable to discern the problem. How should I construct the query?
Only select the SUM(sale.quantity * item.price) in your subquery and remove the select total one.
update Transaction
set total = (
select SUM(sale.quantity * Item.price)
from Sale
inner join Item on Sale.I_ID = Item.I_ID
where Sale.T_ID = Transaction.T_ID
)
That is what I would try out in SQL Server.
I would have prefered to have some sample data so that I can test it against my local SQL Server database in order to verify whether this statement does what is expected, though you're not using SQL Server, the idea is still the same.
EDIT #1
Though I do not fully understand why it does not overwrite values in the transaction.total column when a transaction is composed of several different items, your suggested query works.
The behaviour of the SUM function is to sum all targeted records resulting in only one scalar value for each Sale and Item rows. There can be only one sum, can it not?
That said, it multipies each resulting rows from the constraint, that is, for a particular transaction.
It selects both Sale and Item rows for this very transaction;
It then iterates through each of the resulting rows and multiply Sale.Quantity and Item.Price together, which is worth a value for each row;
Once a row is multiplied, its total is then added to a total which is stored somewhere in memory;
Once it has processed all the rows for that transaction, it comes out with a scalar value, which is the sum of all the rows in Sale and Item for that given transaction;
This SUM ends up to be this transaction's total.
In other words, the subquery "knows" for which transaction to sum which is filtered in the subquery itself. The Transaction table is accessible in the subquery as part of the main SQL statement. So, putting it in the where clause filters the rows from Sale and Item that will be later multiplied and additioned for the total.
Does this help you better understand this update statement?
Please feel free to ask your questions. =)