I have a table as ITEM_LOC with the following format:
ITEM LOC UNIT RETAIL
100 KS 20
101 JS 22
102 RS null
I need to find the unit retail,
if the record if present for loc: RS, it should get that.
If it doesn't exist for RS, it should find for JS.
If it doesn't exist for JS, it should find for KS
and if it doesn't exist of KS, it should return NULL.
How do I go about this case ?
You could do this with a sub-select, that translates the LOC into an number ordered by priority, and which takes the best numeric value present:
SELECT *
FROM ITEM_LOC
WHERE decode(LOC, 'RS', 1, 'JS', 2, 'KS', 3, null) =
(
SELECT min(decode(LOC, 'RS', 1, 'JS', 2, 'KS', 3, 4))
FROM ITEM_LOC
)
Note that if none of these LOC codes exist, you will get an empty result set.
If there are duplicate codes, you can have more than one result.
Related
I have table with dynamic column where I store list of IDs and I have parameter where list of IDs can be passed. So, I want to get rows where any of input values present in table column.
Something like this:
declare query_parameters (
i_ids: dynamic = dynamic([15,33,37])
);
let T = datatable(id: int, ids:dynamic)
[
1, dynamic([10, 15, 18]),
2, dynamic([22,25,29]),
3, dynamic([31, 33, 37]),
];
T
| where ids has_any(i_ids);
I need to get rows 1 and 3 but It fails with message: The source expression is of type 'dynamic' and cannot be compared with numeric arguments.
Can you please help me write proper query?
you can try using set_intersect(): https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/setintersectfunction
declare query_parameters (
i_ids: dynamic = dynamic([15,33,37])
);
let T = datatable(id: int, ids:dynamic)
[
1, dynamic([10, 15, 18]),
2, dynamic([22,25,29]),
3, dynamic([31, 33, 37]),
];
T
| where array_length(set_intersect(ids, i_ids)) > 0
This query returns 1.7763568394002505e-15 when it should return 0.00:
SELECT st.id
, Sum(
CASE sa.Type
WHEN 4 THEN sa.quantity * (st.price - st.commission)
WHEN 5 THEN -sa.quantity * (st.price - st.commission)
ELSE 0.0 END
) Sales
FROM sales sa
JOIN stock st
ON sa.stockid = st.id
WHERE st.id = 1
GROUP BY st.id
http://sqlfiddle.com/#!5/cccd8/3
It's looks like a classic floating point calculation issue, but how can I fix it?
I've tried casting the various columns to REAL but it doesn't make a difference.
You can simulate the result using this query:
SELECT 26.3 - 10.52 - 15.78 AS Result
SQLite's REAL isn't suitable for currency. SQlite doesn't support SQL decimal or SQL numeric data types, so your best option is to use integer, and store values as cents.
CREATE TABLE stock (
id INTEGER,
-- Store price and commission as integers, implying that price is in cents,
-- ($3.20 is stored as 320) and commission is a two-digit percentage (0.57%
-- is stored as 57). This is how scaled integers work in general.
price integer,
commission integer,
PRIMARY KEY(id)
);
CREATE TABLE sales (
id INTEGER,
stockid INTEGER,
type INTEGER,
quantity INTEGER,
PRIMARY KEY(id)
);
insert into stock values (1, 320, 57);
insert into sales values (1, 1, 4, 10);
insert into sales values (2, 1, 5, 4);
insert into sales values (3, 1, 5, 6);
This query, from your SQLfiddle, correctly returns 0.
SELECT st.id
, Sum(
CASE sa.Type
WHEN 4 THEN sa.Quantity * (st.price - st.commission)
WHEN 5 THEN -sa.Quantity * (st.price - st.commission)
ELSE 0.0 END
) Sales
FROM sales sa
JOIN stock st
ON sa.stockid = st.id
WHERE st.id = 1
GROUP BY st.id;
id Sales
---------- ----------
1 0
Casting to a more appropriate data type (not to REAL) will hide some problems--maybe even most problems or even all of them in a particular application. But casting won't solve them, because stored values are liable to be different than the values you really want.
Mike Sherrill is correct in that you probably should use integers. But for a quick-and-dirty fix, you can wrap the Sum call in a Round(__,2) to round to the nearest cent.
I have the following use case where I want to make use of hierarchical queries to get the desired result.
In my use case I have two types of node say 'A' and 'B'. So the unique identifier of node is its ID and Type.
Now the problem is when two nodes with same Id and different type, when I call connect by clause only on id I get child for other types of nodes also (if id of that node is same).
create table TreeTest (
nodeid integer,
nodetype char(1),
parentid integer,
parenttype char(1)
);
Data in table for this particular use case:
1, 'A', NULL, null
2, 'A', 1, 'A'
3, 'A', 1, 'A'
2, 'B', NULL, null
3, 'B', 2, 'B'
Now I am firing the following query (which is not giving the correct result)
SELECT * FROM TREETEST
START WITH PARENTID = 1
CONNECT BY PRIOR nodeid = PARENTID;
I tried following query also, but again wrong result
SELECT * FROM TREETEST
START WITH PARENTID = 1 AND PARENTTYPE = 'A'
CONNECT BY PRIOR nodeid = PARENTID AND NODETYPE = PARENTTYPE;
Kindly provide the correct query and kindly also explain why second query is not working.
Expected output:
2 A 1 A
3 A 1 A
SELECT *
FROM treeTest
START WITH parentId = 1
AND parentType = 'A'
CONNECT BY PRIOR nodeId = parentId
AND PRIOR nodeType = parentType
;
Explanation: PRIOR is an operator applied to a column name, not to the whole condition.
My english won't help to explain what my problem is but i will give a try.
Lets say we have a table with (photoId, _bandId, desc)
Now we have a set of records
1, 1000, TestDesc1
2, 1000, TestDesc2
3, 1010, TestDesc3
4, 1900, TestDesc4
5, 1000, TestDesc5
Im trying to find a select command where gets all the [desc] for a specific [_bandId]
BUT AS FIRST RESULT i want a specific photoId
What i use,
SELECT * FROM [myTable]
WHERE _bandId = (SELECT _bandId from [myTable] where photoId=2)
This of course gives me as output :
TestDesc1
TestDesc2
TestDesc5
BUT what i really need as output is this
TestDesc2
TestDesc1
TestDesc5
Kind Regards
Konstantinos
Add an order by with a case as the first parameter, where you create a value that is 0 for the record that you want first and 1 for the other records. After that you can add more parameters for how you want to sort the remaing records, for example on description:
SELECT
*
FROM
[myTable]
WHERE
_bandId = (SELECT _bandId from [myTable] where photoId=2)
ORDER BY
CASE PhotoId WHEN 2 THEN 0 ELSE 1 END,
[desc]
I have an application which has data spread accross 2 tables.
There is a main table Main which has columns - Id , Name, Type.
Now there is a Sub Main table that has columns - MainId(FK), StartDate,Enddate,city
and this is a 1 to many relation (each main can have multiple entries in submain).
Now I want to display columns Main.Id, City( as comma seperated from various rows for that main item from submain), min of start date(from submain for that main item) and max of enddate( from sub main).
I thought of having a function but that will slow things up since there will be 100k records. Is there some other way of doing this. btw the application is in asp.net. Can we have a sql query or some linq kind of thing ?
This is off the top of my head, but firstly I would suggest you create a user defined function in sql to create the city comma separated list string that accepts #mainid, then does the following:
DECLARE #listStr VARCHAR(MAX)
SELECT #listStr = COALESCE(#listStr+',' , '') + city
FROM submain
WHERE mainid = #mainid
... and then return #listStr which will now be a comma separated list of cities. Let's say you call your function MainIDCityStringGet()
Then for your final result you can simply execute the following
select cts.mainid,
cts.cities,
sts.minstartdate,
sts.maxenddate
from ( select distinct mainid,
dbo.MainIDCityStringGet(mainid) as 'cities'
from submain) as cts
join
( select mainid,
min(startdate) as 'minstartdate',
max(enddate) as 'maxenddate'
from submain
group by mainid ) as sts on sts.mainid = cts.mainid
where startdate <is what you want it to be>
and enddate <is what you want it to be>
Depending on how exactly you would like to filter by startdate and enddate you may need to put the where filter within each subquery and in the second subquery in the join you may then need to use the HAVING grouped filter. You did not clearly state the nature of your filter.
I hope that helps.
This will of course be in stored procedure. May need some debugging.
An alternative to creating a stored procedure is performing the complex operations on the client side. (untested):
var result = (from main in context.Main
join sub in context.SubMain on main.Id equals sub.MainId into subs
let StartDate = subs.Min(s => s.StartDate)
let EndDate = subs.Max(s => s.EndDate)
let Cities = subs.Select(s => s.City).Distinct()
select new { main.Id, main.Name, main.Type, StartDate, EndDate, Cities })
.ToList()
.Select(x => new
{
x.Id,
x.Name,
x.Type,
x.StartDate,
x.EndDate,
Cities = string.Join(", ", x.Cities.ToArray())
})
.ToList();
I am unsure how well this is supported in other implimentations of SQL, but if you have SQL Server this works a charm for this type of scenario.
As a disclaimer I would like to add that I am not the originator of this technique. But I immediately thought of this question when I came across it.
Example:
For a table
Item ID Item Value Item Text
----------- ----------------- ---------------
1 2 A
1 2 B
1 6 C
2 2 D
2 4 A
3 7 B
3 1 D
If you want the following output, with the strings concatenated and the value summed.
Item ID Item Value Item Text
----------- ----------------- ---------------
1 10 A, B, C
2 6 D, A
3 8 B, D
The following avoids a multi-statement looping solution:
if object_id('Items') is not null
drop table Items
go
create table Items
( ItemId int identity(1,1),
ItemNo int not null,
ItemValue int not null,
ItemDesc nvarchar(500) )
insert Items
( ItemNo,
ItemValue,
ItemDesc )
values ( 1, 2, 'A'),
( 1, 2, 'B'),
( 1, 6, 'C'),
( 2, 2, 'D'),
( 2, 4, 'A'),
( 3, 7, 'B'),
( 3, 1, 'D')
select it1.ItemNo,
sum(it1.ItemValue) as ItemValues,
stuff((select ', ' + it2.ItemDesc --// Stuff is just used to remove the first 2 characters, instead of a substring.
from Items it2 with (nolock)
where it1.ItemNo = it2.ItemNo
for xml path(''), type).value('.','varchar(max)'), 1, 2, '') as ItemDescs --// Does the actual concatenation..
from Items it1 with (nolock)
group by it1.ItemNo
So you see all you need is a sub query in your select that retrieves a set of all the values you need to concatenate and then use the FOR XML PATH command in that sub query in a clever way. It does not matter where the values you need to concatenate comes from you just need to retrieve them using the sub query.