I have the following query:
select act.Division
, act.DivisionName
, act.code
, act.name
, act.status
, acs.description
, act.IsSupplier
, act.IsSales
from exactonlinerest..accounts act
left
outer
join accountcustomerstatuses acs
on acs.code = act.status
order
by Division
, code
Some results give back a status of C (customer) and a true on supplier. IsSales is sometimes true and sometimes false.
I am confused about the meaning of these values. The documentation is not clear on the purpose.
Would that account be both a customer AND a supplier?
What is the meaning of issales?
See answer on documentation:
Each counterparty is registered at most once as an account. Their type can be determined using a number of methods:
Customer: the column 'Status' has the value 'C' when the account is a customer. The meaning of the status codes is described in the table 'AccountStatuses'.
Prospect: the column 'Status' has the value 'P' when the account is a prospect.
Suspect: the column 'Status' has the value 'S' when the account is a suspect.
Reseller: the column 'IsReseller' has the boolean value 'true'.
Supplier: the column 'IsSupplier' has the boolean value 'true'.
Accountant: the column 'IsAccountant' has the boolean value 'true'.
Competitor: the column 'IsCompetitor' has the boolean value 'true'.
Related
I have 3 tables in my DB; Transactions, transaction_details, and accounts - basically as below.
transactions :
id
details
by_user
created_at
trans_details :
id
trans_id (foreign key)
account_id
account_type (Enum -[c,d])
amount
Accounts :
id
sub_name
In each transaction each account may be creditor or debtor. What I'm trying to get is an account statement (ex : bank account movements) so I need to query each movement when the account is type = c (creditor) or the account type is = d (debtor)
trans_id, amount, created_at, creditor_account, debtor_account
Update : I tried the following query but i get the debtor column values all Null!
SELECT transactions.created_at,trans_details.amount,(case WHEN trans_details.type = 'c' THEN sub_account.sub_name END) as creditor,
(case WHEN trans_details.type = 'd' THEN sub_account.sub_name END) as debtor from transactions
JOIN trans_details on transactions.id = trans_details.trans_id
JOIN sub_account on trans_details.account_id = sub_account.id
GROUP by transactions.id
After the help of #Jalos I had to convert the query to Laravel which also toke me 2 more hours to convert and get the correct result :) below is the Laravel code in case some one needs to perform such query
I also added between 2 dates functionality
public function accountStatement($from_date,$to_date)
{
$statemnt = DB::table('transactions')
->Join('trans_details as credit_d',function($join) {
$join->on('credit_d.trans_id','=','transactions.id');
$join->where('credit_d.type','c');
})
->Join('sub_account as credit_a','credit_a.id','=','credit_d.account_id')
->Join('trans_details as debt_d',function($join) {
$join->on('debt_d.trans_id','=','transactions.id');
$join->where('debt_d.type','d');
})
->Join('sub_account as debt_a','debt_a.id','=','debt_d.account_id')
->whereBetween('transactions.created_at',[$from_date,$to_date])
->select('transactions.id','credit_d.amount','transactions.created_at','credit_a.sub_name as creditor','debt_a.sub_name as debtor')
->get();
return response()->json(['status_code'=>2000,'data'=>$statemnt , 'message'=>''],200);
}
Your transactions table denotes transaction records, while your accounts table denotes account records. Your trans_details table denotes links between transactions and accounts. So, since in a transaction there is a creditor and a debtor, I assume that trans_details has exactly two records for each transaction:
select transactions.id, creditor_details.amount, transactions.created_at, creditor.sub_name, debtor.sub_name
from transactions
join trans_details creditor_details
on transactions.id = creditor_details.trans_id and creditor_details.account_type = 'c'
join accounts creditor
on creditor_details.account_id = creditor.id
join trans_details debtor_details
on transactions.id = debtor_details.trans_id and debtor_details.account_type = 'd'
join accounts debtor
on debtor_details.account_id = debtor.id;
EDIT
As promised, I am looking into the query you have written. It looks like this:
SELECT transactions.id,trans_details.amount,(case WHEN trans_details.type = 'c' THEN account.name END) as creditor,
(case WHEN trans_details.type = 'd' THEN account.name END) as debtor from transactions
JOIN trans_details on transactions.id = trans_details.trans_id
JOIN account on trans_details.account_id = account.id
GROUP by transactions.id
and it is almost correct. The problem is that due to the group-by MySQL can only show a single value for each record for creditor and debtor. However, we know that there are exactly two values for both: there is a null value for creditor when you match with debtor and a proper creditor value when you match with creditor. The case for debtor is similar. My expectation for this query would have been that MySQL would throw an error because you did not group by these computed case-when fields, yet, there are several values, but it seems MySQL can surprise me after so many years :)
From the result we see that MySQL probably found the first value and used that both for creditor and debtor. Since it met with a creditor match as a first match, it had a proper creditor value and a null debtor value. However, if you write bullet-proof code, you will never meet these strange behavior. In our case, doing some minimalistic improvements on your code transforms it into a bullet-proof version of it and provides correct results:
SELECT transactions.id,trans_details.amount,max((case WHEN trans_details.type = 'c' THEN account.name END)) as creditor,
max((case WHEN trans_details.type = 'd' THEN account.name END)) as debtor from transactions
JOIN trans_details on transactions.id = trans_details.trans_id
JOIN account on trans_details.account_id = account.id
group by transactions.id
Note, that the only change I did with your code is to wrap a max() function call around the case-when definitions, so we avoid the null values, so your approach was VERY close to a bullet-proof solution.
Fiddle: http://sqlfiddle.com/#!9/d468dc/10/0
However, even though your thought process was theoretically correct (theoretically there is no difference between theory and practice, but in practice they are usually different) and some slight changes are transforming it into a well-working code, I still prefer my query, because it avoids group by clauses, which can be useful, if necessary, but here it's unnecessary to do group by, which is probably better in terms of performance, memory usage, it's easier to read and keeps more options open for you for your future customisations. Yet, your try was very close to a solution.
As about my query, the trick I used was to do several joins with the same tables, aliasing them and from that point differentiating them as if they were different tables. This is a very useful trick that you will need a lot in the future.
I have four tables for a form-builder in my databse.
fields (fieldID(PK), typeID, fieldName, ...) - This table is a row by row list of all fields to be in the form
fields_types (typeID(PK), htmlType, ...) - This is a table that links fields to html types (and other settings)
fields_meta (FieldMetaID(PK), FieldID, mName, mValue) - Additional settings for fields, but more specific. A textarea field might have a height attribute, but almost no other field would use that.
fields_tyeps_meta (TypeMetaID(PK), typeID, tmName, tmValue) - Defines what extraneous settings a field can have, and also supplies default values if it's not explicitly set)
So my Query currently looks something like this
SELECT *
FROM Fields F
JOIN Field_Types FT
on FT.FieldID = F.FieldID
LEFT
JOIN Field_Meta FM
on FM.FieldID = F.FieldID
I was wondering if there's a way to join Fields_Types_Meta so that when the row's JOIN to Fields_Meta doesn't return a row (no mValue), it returns tmValue
I realize I can use something like (CASE WHEN mValue = "" THEN tmValue ELSE mValue END) AS UseValue, but I might have fields where I want to allow the value to be set to empty.
Edit: I could probably do something with a subquery and COUNT, using a CASE decision based on that. It might not be the healthiest performance-wise, but this query runs and caches itself til server restart, or until it's told to run again (updates to form design)
It looks like you just want ¢oalesce():
coalesce(FM.mValue, FT.tmValue) as UseValue
When FM.mValue is null, coalesce() returns FT.tmValue instead.
If you have null values in FM that you want to preserve in the result set, then use a case expression instead:
case when FM.FieldID IS NULL THEN FT.tmValue ELSE FM.mValue END as UseValue
This phrases as: when the left join did find a match in FM, use mValue from that row (even if it is null), else use FT.tmValue.
i am trying to make a view in MS SQL having join of two table and an individual field.
i have done the joining part but now i want to add a new field in this view which is not in any of the table which is joined.
so anybody have any idea how i can create this new field in the view.
In case you want a default value for all your rows in the ACTIVE field, try this
CREATE VIEW Slots AS
SELECT Event.EventId,
Event.eventName,
examCenter.centerId,
examCenter.centerName,
slotTime.slotTimeId,
slotTime.FromTime,
slotTime.ToTime,
slotTime.Dated,
examCenter.noOfSeats,
CAST(1 AS bit) AS Active
FROM examCenter
INNER JOIN Event
ON examCenter.eventId = Event.EventId
INNER JOIN slotTime ON Event.EventId = slotTime.eventId
If the value for the ACTIVE field depends on some condition, say
slottime.Dated => getdate()
then, you will need to replace
CAST(1 AS bit) AS Active
in the above code, with
CAST(CASE WHEN slottime.Dated => getdate() THEN 1 ELSE 0 AS bit) AS ACTIVE
You can explicitly name each field if you need, aliasing them with AS as required. For example:
SELECT si.field1 as si_field1,
si.field2 as si_field2,
ind_data.field1 as ind_data_field1
FROM sites_indexed as si
LEFT JOIN individual_data as ind_data
ON si.id = ind_data.site_id
And then you can reference the aliased names in your result set.
I have a view with computed columns now I need to enforce the computed columns to be "not null" for lightswitch.
I tried to cast() but I still cant get the computed columns to be "not null"
Is it possible?
This is my SQL:
SELECT dbo.Nop_Manufacturer.Name,
CAST(SUM(dbo.Nop_OrderProductVariant.PriceExclTax) AS INT) AS
SALES,
CAST(MONTH(dbo.Nop_Order.PaidDate) AS INT) AS
paid_month,
CAST(YEAR(dbo.Nop_Order.PaidDate) AS INT) AS
paid_year,
CAST(COUNT(dbo.Nop_OrderProductVariant.OrderProductVariantID) AS INT)AS
num_prod_sold
FROM dbo.Nop_ProductVariant
INNER JOIN dbo.Nop_OrderProductVariant
ON dbo.Nop_ProductVariant.ProductVariantId =
dbo.Nop_OrderProductVariant.ProductVariantID
INNER JOIN dbo.Nop_Product
ON dbo.Nop_ProductVariant.ProductID = dbo.Nop_Product.ProductId
INNER JOIN dbo.Nop_Product_Manufacturer_Mapping
INNER JOIN dbo.Nop_Manufacturer
ON dbo.Nop_Product_Manufacturer_Mapping.ManufacturerID =
dbo.Nop_Manufacturer.ManufacturerID
ON dbo.Nop_Product.ProductId =
dbo.Nop_Product_Manufacturer_Mapping.ProductID
INNER JOIN dbo.Nop_Order
ON dbo.Nop_OrderProductVariant.OrderID = dbo.Nop_Order.OrderID
WHERE ( NOT ( dbo.Nop_Order.PaidDate IS NULL ) )
GROUP BY dbo.Nop_Manufacturer.Name,
MONTH(dbo.Nop_Order.PaidDate),
YEAR(dbo.Nop_Order.PaidDate)
CAST-ing as INT won't do anything to affect the perceived nullability of computed columns. You need to wrap them in ISNULL instead.
e.g. ISNULL(YEAR(dbo.Nop_Order.PaidDate),0)
This is documented in the last paragraph here
The Database Engine automatically determines the nullability of
computed columns based on the expressions used. The result of most
expressions is considered nullable even if only nonnullable columns
are present, because possible underflows or overflows will produce
null results as well. Use the COLUMNPROPERTY function with the
AllowsNull property to investigate the nullability of any computed
column in a table. An expression that is nullable can be turned into a
nonnullable one by specifying ISNULL(check_expression, constant),
where the constant is a nonnull value substituted for any null result.
There are 3 tables. Products, Options and Prod_Opts_relations. The latter holds product_id and option_id so i should be able to figure out which options are selected for any given product.
Now i want to retrieve all options from the options table where the value of an extra alias field should hold checked or unchecked depending on the existance of a mathing record in the relations table for a give product id.
Thus far i came up with this:
SELECT
IF(IN(SELECT id_option FROM prod_opt_relations WHERE id_product='18'),'y','n') AS booh
,optionstable.id AS parent_id
,optionstable.name_en AS parent_english
,optionstable.name_es AS parent_spanish
FROM product_options AS optionstable
WHERE 1
resulting in syntax errors.
Alas i just cannot figure out where things go wrong here
Use a left join between your two tables to retrieve all the data from the option table whenever there is a match or not. Then test if the value return from the right table is null to set your y/n flag.
SELECT
IF(por.id_product IS NULL, 'n', 'y') AS booh
,optionstable.id AS parent_id
,optionstable.name_en AS parent_english
,optionstable.name_es AS parent_spanish
FROM
product_options AS optionstable
LEFT JOIN prod_opt_relations as por ON (
por.id_product=18 AND por.id_option=optionstable.id_option
)
WHERE 1
You did not specify which expression should be compared to your IN-list:
IF( foo IN (...), 'y', 'n')
edit: Your statement lacks an equivalent to what is foo in this example.
See http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in