Get distinct results from database that has a "dictionary" - sql

I have a database with a "dictionary" like this:
Id (INT) | Key (VARCHAR) | Value (VALUE) | ForeignKey (INT?)
------------------------------------------------------------
1 | foo | bar | 23
2 | bar | foo | NULL
3 | foobar | value | NULL
4 | foobar | othervalue | 47
Now I want to get all keys and values for a specific foreign key, but also all foreign keys that are NULL, so that the result looks like this:
ForeignKey = 23: ForeignKey = 47:
foo | bar bar | foo
bar | foo foobar | othervalue
foobar | value
Originally I tried this approach:
dbContext.Table
.Where(t => t.ForeignKey == 47 || t.ForeignKey == null)
but that gives me foobar twice.
I then though about multiple requests and unionizing the results:
var t1 = _dbContext.Table
.Where(t => t.ForeignKey == 47);
var t2 = _dbContext.Table
.Where(t => t.ForeignKey == null && !t1.Any(tt => tt.Key == t.Key));
var final = t1.Union(t2);
This seemingly works, but it creates this SQL (roughly) which seems excessive with three SELECT, three WHERE and a UNION
SELECT [t1].[Id], [t1].[Key], [t1].[Value], [t1].ForeignKey
FROM [Table] AS [t1]
WHERE [t1].[ForeignKey] = 47
UNION
SELECT [t2].[Id], [t2].[Key], [t2].[Value], [t2].ForeignKey
FROM [Table] AS [t2]
WHERE [t2].[ForeignKey] IS NULL AND NOT (EXISTS (
SELECT 1
FROM [Table] AS [t3]
WHERE ([t3].[ForeignKey] = 47) AND ([t3].[Key] = [t2].[Key])))
I just have a gut feeling that "there's got to be a better way"... so, is there? How can I get keys and values for a specific foreign key, but also keys not already fetched that are NULL?

The SQL you're seeing doesn't seem excessive to me. Unless you've tested this and found it to have unacceptably bad performance, I wouldn't necessarily spend too much time trying to optimize it.
Here's an alternative approach, though, which may be preferable. You'd have to do some testing to see if it yields better SQL, execution plan, and performance. Mostly I'd go with whichever approach will be easier for other developers to understand.
var final = dbContext.Table.Where(t => t.ForeignKey == 47 || t.ForeignKey == null)
.GroupBy(t => t.Key)
.Select(g => g.OrderBy(t => t.ForeignKey == null ? 1 : 0).FirstOrDefault());

Related

KQL :: return only tags with more than 4 records

I have created a Kusto query that allows me to return all our database park. The query only takes 10 lines of code:
Resources
| join kind=inner (
resourcecontainers
| where type == 'microsoft.resources/subscriptions'
| project subscriptionId, subscriptionName = name)
on subscriptionId
| where subscriptionName in~ ('Subscription1','Subscription2')
| where type =~ 'microsoft.sql/servers/databases'
| where name != 'master'
| project subscriptionName, resourceGroup, name, type, location,sku.tier, properties.requestedServiceObjectiveName, tags.customerCode
By contract we are supposed to give only 4 Azure SQL Database per customer but sometimes developers take a copy of them and they rename it _old or _backup and suddenly a customer can have 5 or 6 databases.
This increase the overall costs of the Cloud and I would like to have a list of all customers that have more than 4 databases.
In order to do so I can use the tag tags.customerCode which has the 3 letters identifier for each customer.
The code should work like this: if a customer is called ABC and there are 4 Azure SQL Databases with tags.customerCode ABC the query should return nothing. If there are 5 or 6 databases with tags.customerCode ABC the query should return all of them.
Not sure if Kusto can be that flexible.
Here is a possible solution.
It should be noted that Azure resource graph supports only a limited subset of KQL.
resourcecontainers
| where type == 'microsoft.resources/subscriptions'
//and name in~ ('Subscription1','Subscription2')
| project subscriptionId, subscriptionName = name
| join kind=inner
(
resources
| where type =~ 'microsoft.sql/servers/databases'
and name != 'master'
)
on subscriptionId
| project subscriptionId, subscriptionName, resourceGroup, name, type, location
,tier = sku.tier
,requestedServiceObjectiveName = properties.requestedServiceObjectiveName
,customerCode = tostring(tags.customerCode)
| summarize dbs = count(), details = make_list(pack_all()) by customerCode
| where dbs > 4
| mv-expand with_itemindex=db_seq ['details']
| project customerCode
,dbs
,db_seq = db_seq + 1
,subscriptionId = details.subscriptionId
,subscriptionName = details.subscriptionName
,resourceGroup = details.resourceGroup
,name = details.name
,type = details.type
,location = details.location
,tier = details.tier
,requestedServiceObjectiveName = details.requestedServiceObjectiveName

magento: join product with attribute value

I'm trying to list some of my product from a php script and I need to get some attributes's value. For exemple I'm trying something like this::
Mage::app();
Mage::app()->setCurrentStore(1);
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('computer_type')
->joinAttribute('computer_type_value', 'eav/entity_attribute_option', "computer_type", null, 'left', 0)
"computer_type" from product collection store an id which is found in option_id field of the eav_attribute_option_value table:
+----------+-----------+----------+--------+
| value_id | option_id | store_id | value |
+----------+-----------+----------+--------+
| 3738 | 14 | 0 | server |
+----------+-----------+----------+--------+
I would like to join this table with my collection's result in order to have the value "server" displayed instead of the id "3738" but the way I'm doing it is not working and despite all my search.
I didn't find how to achieve that in only one query. Is it possible ?
Please use below code for join product attribute:
$mageFilename = 'app/Mage.php';
require_once $mageFilename;
umask(0);
Mage::app('admin');
Mage::register('isSecureArea', 1);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addAttributeToFilter('computer_type',array('neq'=>0))
->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
->addAttributeToFilter('visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);

Lithium Model find query with <> operator

I'm trying to fetch rows excluding the one which already are in an other table :
| Content | ContentSelected
| –––––––– | ––––––––––––––––––––––––-
| id | content_id | operation_id
| 1 | 1 | 9999
| 2 | 3 | 1000
| 3
=> 2,3
Here how I tried to run this query :
Content::find('all', array(
'joins' => array(new Query(array(
'source' => 'ContentSelected',
'constraints' => array('ContentSelected.operation_id' => 9999),
'conditions' => array(
'Content.id' => array('<>' => 'ContentSelected.content_id')
));
Here the SQL query run by the adapter :
SELECT * FROM "Content" AS "Content"
JOIN "ContentSelected" ON "ContentSelected"."operation_id" = 1
WHERE ("Content"."id" <> 0);
Is there another way to performed a query excluding results, or to force the adapter to write ContentSelected.content_id instead of 0 in the where clause ?
Thanks
You can use Model::connection()->read() to run a native sql in Li3. Check this out http://www.jblotus.com/2011/10/25/executing-raw-mysql-queries-in-lithium/
Content::connection()->read($your_sql);
But before using such a solution. Try to implement your model properly using Model Relationships (http://li3.me/docs/manual/models/relationships.md) so that you don't need to use a native query and let the model does the work for you.

Find matching tag items in table from string array using linq

I have a SQL table of tags like this:
Id | Tag
-----------------
1 | car
1 | red
1 | sport
2 | car
2 | red
2 | SUV
And I want to retrieve ONLY the ID for exact matching search strings. So, using LINQ, I'd like to query for:
"car,red"
and have it return: 1 and 2.
Then searching for "car,red,sport" would return 1 only.
I'm not sure at all how to do this using LINQ. If I do the following (using EF context and table as example):
string[] tags = {"car","red","sport"}
var query = context.CarTags.Where(a => tags.Contains(a.Tag)).Select(s=>s);
...will of course return both 1 & 2.
So, how do I do this using LINQ?
string[] tags = {"car","red","sport"}
var query = context.CarTags
.GroupBy(a => a.Id)
.Where(g => tags.All(t => g.Any(a => a.Tag == t)))
.Select(g => g.Key);
I'm not sure if it's gonna work with LINQ to Entites, but would definitely give it a try.
All methods used are listed as supported within Supported and Unsupported LINQ Methods (LINQ to Entities) list, so should work. But even if it is, I would probably check the generated SQL to make sure it's not over-complicated and not very effective.

How can I turn a single row column into a scalar in SQL?

This is sort of what I want to do, but MySQL doesn't seem to accept it.
SELECT Name, Content, Lft, Rht FROM Articles WHERE
(Lft > (SELECT Lft FROM Articles WHERE idArticle = 1))
AND WHERE
(Rht < (SELECT Rht FROM Articles WHERE idArticle = 1));
I'm implementing the modified preorder tree transversal algorithm, and I want to get all the children of an Article using a single database query.
The Articles table looks like this:
Articles
+=============+===========+
| Type | Name |
+=============+===========+
| VARCHAR(45) | Name |
+-------------+-----------+
| LONGTEXT | Content |
+-------------+-----------+
| INT | Lft |
+-------------+-----------+
| INT | Rht |
+-------------+-----------+
| INT | idArticle |
+-------------+-----------+
idArticle is a primary key, and there are UNIQUE indexes on the Lft and Rht columns.
How might something like this be accomplished?
*Note: I'm currently using MySQL but I'd like to avoid any MySQL extensions where possible, because there are possible plans to move to another DB like Postgres or Oracle sometime in the future...
It's not being accepted because the WHERE keyword can only appear once in a query (outside of a subquery):
SELECT x.name,
x.content,
x.lft,
x.rht
FROM ARTICLES x
WHERE EXISTS(SELECT NULL
FROM ARTICLES y
WHERE y.idarticle = 1
AND y.lft < x.lft)
AND EXISTS(SELECT NULL
FROM ARTICLES z
WHERE z.idarticle = 1
AND z.rht > x.rht)
Apparently it was just a simple syntax error (too many WHERE), but if you want to avoid the scalar subselect, you could also do a join (with the potential advantage that the row with idArticle 1 only needs to be loaded once, an optimization that your query planner may or may not be able to figure out by itself):
SELECT a.Name, a.Content, a.Lft, a.Rht FROM Articles a
join Articles b on (b.idArticle =1 )
where a.lft > b.lft and a.rht < b.rht;
Alternate equivalent
SELECT a.Name, a.Content, a.Lft, a.Rht
FROM Articles a
join Articles b on a.lft > b.lft
and a.rht < b.rht
AND b.idArticle = 1 ;